1
- from django .core .exceptions import FieldError
2
1
from django .db .backends .base .schema import BaseDatabaseSchemaEditor
3
2
from django .db .models import Index
4
3
from pymongo .operations import IndexModel
@@ -58,91 +57,25 @@ def add_field(self, model, field):
58
57
index .name = self ._create_index_name (model ._meta .db_table , [field .column ])
59
58
self .add_index (model , index , field = field )
60
59
61
- def alter_field (self , model , old_field , new_field , strict = False , old_db_table = None ):
62
- """
63
- Allow a field's type, uniqueness, nullability, default, column,
64
- constraints, etc. to be modified.
65
- `old_field` is required to compute the necessary changes.
66
- If `strict` is True, raise errors if the old column does not match
67
- `old_field` precisely.
68
-
69
- This is identical to the base class except `old_db_table` is added.
70
- """
71
- if not self ._field_should_be_altered (old_field , new_field ):
72
- return
73
- # Ensure this field is even column-based
74
- old_db_params = old_field .db_parameters (connection = self .connection )
75
- old_type = old_db_params ["type" ]
76
- new_db_params = new_field .db_parameters (connection = self .connection )
77
- new_type = new_db_params ["type" ]
78
- modifying_generated_field = False
79
- if (old_type is None and old_field .remote_field is None ) or (
80
- new_type is None and new_field .remote_field is None
81
- ):
82
- raise ValueError (
83
- f"Cannot alter field { old_field } into { new_field } - they do "
84
- "not properly define db_type (are you using a badly-written "
85
- "custom field?)"
86
- )
87
- if (
88
- old_type is None
89
- and new_type is None
90
- and (
91
- old_field .remote_field .through
92
- and new_field .remote_field .through
93
- and old_field .remote_field .through ._meta .auto_created
94
- and new_field .remote_field .through ._meta .auto_created
95
- )
96
- ):
97
- self ._alter_many_to_many (model , old_field , new_field , strict )
98
- return
99
- if (
100
- old_type is None
101
- and new_type is None
102
- and (
103
- old_field .remote_field .through
104
- and new_field .remote_field .through
105
- and not old_field .remote_field .through ._meta .auto_created
106
- and not new_field .remote_field .through ._meta .auto_created
107
- )
108
- ):
109
- # Both sides have through models; this is a no-op.
110
- return
111
- if old_type is None or new_type is None :
112
- raise ValueError (
113
- f"Cannot alter field { old_field } into { new_field } - they are "
114
- "not compatible types (you cannot alter to or from M2M fields, "
115
- "or add or remove through= on M2M fields)"
116
- )
117
- if old_field .generated != new_field .generated or (
118
- new_field .generated and old_field .db_persist != new_field .db_persist
119
- ):
120
- modifying_generated_field = True
121
- elif new_field .generated :
122
- try :
123
- old_field_sql = old_field .generated_sql (self .connection )
124
- except FieldError :
125
- # Field used in a generated field was renamed.
126
- modifying_generated_field = True
127
- else :
128
- new_field_sql = new_field .generated_sql (self .connection )
129
- modifying_generated_field = old_field_sql != new_field_sql
130
- if modifying_generated_field :
131
- raise ValueError (
132
- f"Modifying GeneratedFields is not supported - the field { new_field } "
133
- "must be removed and re-added with the new definition."
134
- )
135
- self ._alter_field (
60
+ def _drop_index_for_field (self , collection , model , field ):
61
+ # Find the index for this field
62
+ meta_index_names = {index .name for index in model ._meta .indexes }
63
+ # Retrieve only BTREE indexes since this is what's created with
64
+ # db_index=True.
65
+ index_names = self ._constraint_names (
136
66
model ,
137
- old_field ,
138
- new_field ,
139
- old_type ,
140
- new_type ,
141
- old_db_params ,
142
- new_db_params ,
143
- strict ,
144
- old_db_table ,
67
+ [field .column ],
68
+ index = True ,
69
+ type_ = Index .suffix ,
70
+ exclude = meta_index_names ,
145
71
)
72
+ if not index_names :
73
+ raise ValueError (f"Index not found for { model ._meta .db_table } .{ field .column } ." )
74
+ for index_name in index_names :
75
+ # The only way to check if an index was created with
76
+ # db_index=True or with Index(['field'], name='foo')
77
+ # is to look at its name (refs #28053).
78
+ collection .drop_index (index_name )
146
79
147
80
def _alter_field (
148
81
self ,
@@ -154,7 +87,6 @@ def _alter_field(
154
87
old_db_params ,
155
88
new_db_params ,
156
89
strict = False ,
157
- old_db_table = None ,
158
90
):
159
91
collection = self .connection .database [model ._meta .db_table ]
160
92
# Removed an index? (no strict check, as multiple indexes are possible)
@@ -172,31 +104,15 @@ def _alter_field(
172
104
and not old_field .unique
173
105
and (not new_field .db_index or new_field .unique )
174
106
):
175
- # Find the index for this field
176
- meta_index_names = {index .name for index in model ._meta .indexes }
177
- # Retrieve only BTREE indexes since this is what's created with
178
- # db_index=True.
179
- index_names = self ._constraint_names (
180
- model ,
181
- [old_field .column ],
182
- index = True ,
183
- type_ = Index .suffix ,
184
- exclude = meta_index_names ,
185
- )
186
- for index_name in index_names :
187
- # The only way to check if an index was created with
188
- # db_index=True or with Index(['field'], name='foo')
189
- # is to look at its name (refs #28053).
190
- collection .drop_index (index_name )
107
+ self ._drop_index_for_field (collection , model , old_field )
191
108
# Have they renamed the column?
192
109
if old_field .column != new_field .column :
193
110
collection .update_many ({}, {"$rename" : {old_field .column : new_field .column }})
194
111
# Move index to the new field, if needed.
195
- if old_field .db_index and new_field .db_index :
196
- old_db_table = old_db_table or model ._meta .db_table
197
- old_index = Index (fields = [old_field .name ])
198
- old_index .name = self ._create_index_name (old_db_table , [old_field .column ])
199
- self .remove_index (model , old_index )
112
+ if self ._field_should_be_indexed (model , old_field ) and self .__field_should_be_indexed (
113
+ model , new_field
114
+ ):
115
+ self ._drop_index_for_field (collection , model , old_field )
200
116
new_index = Index (fields = [new_field .name ])
201
117
new_index .name = self ._create_index_name (model ._meta .db_table , [new_field .column ])
202
118
self .add_index (model , new_index , field = new_field )
@@ -224,40 +140,6 @@ def _alter_field(
224
140
index .name = self ._create_index_name (model ._meta .db_table , [new_field .column ])
225
141
self .add_index (model , index )
226
142
227
- def _alter_many_to_many (self , model , old_field , new_field , strict ):
228
- """
229
- Alter M2Ms to repoint their to= endpoints.
230
-
231
- This is identical to the base class except `old_db_table=...` is added.
232
- """
233
- # Rename the through table
234
- if (
235
- old_field .remote_field .through ._meta .db_table
236
- != new_field .remote_field .through ._meta .db_table
237
- ):
238
- self .alter_db_table (
239
- old_field .remote_field .through ,
240
- old_field .remote_field .through ._meta .db_table ,
241
- new_field .remote_field .through ._meta .db_table ,
242
- )
243
- # Repoint the FK to the other side
244
- self .alter_field (
245
- new_field .remote_field .through ,
246
- # The field that points to the target model is needed, so we can
247
- # tell alter_field to change it - this is m2m_reverse_field_name()
248
- # (as opposed to m2m_field_name(), which points to our model).
249
- old_field .remote_field .through ._meta .get_field (old_field .m2m_reverse_field_name ()),
250
- new_field .remote_field .through ._meta .get_field (new_field .m2m_reverse_field_name ()),
251
- old_db_table = old_field .remote_field .through ._meta .db_table ,
252
- )
253
- self .alter_field (
254
- new_field .remote_field .through ,
255
- # for self-referential models we need to alter field from the other end too
256
- old_field .remote_field .through ._meta .get_field (old_field .m2m_field_name ()),
257
- new_field .remote_field .through ._meta .get_field (new_field .m2m_field_name ()),
258
- old_db_table = old_field .remote_field .through ._meta .db_table ,
259
- )
260
-
261
143
def remove_field (self , model , field ):
262
144
# Remove implicit M2M tables.
263
145
if field .many_to_many and field .remote_field .through ._meta .auto_created :
0 commit comments