diff --git a/django/core/management/validation.py b/django/core/management/validation.py
index 56708e1..b2f7da5 100644
a
|
b
|
class ModelErrorCollection:
|
15 | 15 | self.errors.append((context, error)) |
16 | 16 | self.outfile.write(self.style.ERROR("%s: %s\n" % (context, error))) |
17 | 17 | |
| 18 | |
18 | 19 | def get_validation_errors(outfile, app=None): |
19 | 20 | """ |
20 | 21 | Validates all models that are part of the specified app. If no app name is provided, |
… |
… |
def get_validation_errors(outfile, app=None):
|
72 | 73 | e.add(opts, '"%s": Field\'s name must not contain "%s".' % ( |
73 | 74 | f.name, LOOKUP_SEP)) |
74 | 75 | if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': |
75 | | e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name) |
| 76 | e.add(opts, '"%s": You can\'t use "id" as a field name, because ' |
| 77 | 'each model automatically gets an "id" field ' |
| 78 | 'if none of the fields have primary_key=True. ' |
| 79 | 'You need to either remove/rename your "id" field ' |
| 80 | 'or add primary_key=True to a field.' % f.name) |
76 | 81 | if f.name.endswith('_'): |
77 | | e.add(opts, '"%s": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.' % f.name) |
| 82 | e.add(opts, '"%s": Field names cannot end with underscores, ' |
| 83 | 'because this would lead to ambiguous queryset filters.' % |
| 84 | f.name) |
78 | 85 | if (f.primary_key and f.null and |
79 | 86 | not connection.features.interprets_empty_strings_as_nulls): |
80 | 87 | # We cannot reliably check this for backends like Oracle which |
… |
… |
def get_validation_errors(outfile, app=None):
|
85 | 92 | try: |
86 | 93 | max_length = int(f.max_length) |
87 | 94 | if max_length <= 0: |
88 | | e.add(opts, '"%s": CharFields require a "max_length" attribute that is a positive integer.' % f.name) |
| 95 | e.add(opts, '"%s": CharFields require a "max_length" attribute ' |
| 96 | 'that is a positive integer.' % f.name) |
89 | 97 | except (ValueError, TypeError): |
90 | | e.add(opts, '"%s": CharFields require a "max_length" attribute that is a positive integer.' % f.name) |
| 98 | e.add(opts, '"%s": CharFields require a "max_length" attribute ' |
| 99 | 'that is a positive integer.' % f.name) |
91 | 100 | if isinstance(f, models.DecimalField): |
92 | 101 | decimalp_ok, mdigits_ok = False, False |
93 | | decimalp_msg ='"%s": DecimalFields require a "decimal_places" attribute that is a non-negative integer.' |
| 102 | decimalp_msg = ('"%s": DecimalFields require a "decimal_places" attribute ' |
| 103 | 'that is a non-negative integer.') |
94 | 104 | try: |
95 | 105 | decimal_places = int(f.decimal_places) |
96 | 106 | if decimal_places < 0: |
… |
… |
def get_validation_errors(outfile, app=None):
|
99 | 109 | decimalp_ok = True |
100 | 110 | except (ValueError, TypeError): |
101 | 111 | e.add(opts, decimalp_msg % f.name) |
102 | | mdigits_msg = '"%s": DecimalFields require a "max_digits" attribute that is a positive integer.' |
| 112 | mdigits_msg = ('"%s": DecimalFields require a "max_digits" attribute ' |
| 113 | 'that is a positive integer.') |
103 | 114 | try: |
104 | 115 | max_digits = int(f.max_digits) |
105 | 116 | if max_digits <= 0: |
… |
… |
def get_validation_errors(outfile, app=None):
|
108 | 119 | mdigits_ok = True |
109 | 120 | except (ValueError, TypeError): |
110 | 121 | e.add(opts, mdigits_msg % f.name) |
111 | | invalid_values_msg = '"%s": DecimalFields require a "max_digits" attribute value that is greater than or equal to the value of the "decimal_places" attribute.' |
| 122 | invalid_values_msg = ('"%s": DecimalFields require a "max_digits" ' |
| 123 | 'attribute value that is greater than or equal to ' |
| 124 | 'the value of the "decimal_places" attribute.') |
112 | 125 | if decimalp_ok and mdigits_ok: |
113 | 126 | if decimal_places > max_digits: |
114 | 127 | e.add(opts, invalid_values_msg % f.name) |
… |
… |
def get_validation_errors(outfile, app=None):
|
122 | 135 | try: |
123 | 136 | import Image |
124 | 137 | except ImportError: |
125 | | e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name) |
| 138 | e.add(opts, '"%s": To use ImageFields, you need to install ' |
| 139 | 'the Python Imaging Library. Get it ' |
| 140 | 'at http://www.pythonware.com/products/pil/ .' % f.name) |
126 | 141 | if isinstance(f, models.BooleanField) and getattr(f, 'null', False): |
127 | | e.add(opts, '"%s": BooleanFields do not accept null values. Use a NullBooleanField instead.' % f.name) |
| 142 | e.add(opts, '"%s": BooleanFields do not accept null values. ' |
| 143 | 'Use a NullBooleanField instead.' % f.name) |
128 | 144 | if f.choices: |
129 | 145 | if isinstance(f.choices, basestring) or not is_iterable(f.choices): |
130 | | e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name) |
| 146 | e.add(opts, '"%s": "choices" should be iterable ' |
| 147 | '(e.g., a tuple or list).' % f.name) |
131 | 148 | else: |
132 | 149 | for c in f.choices: |
133 | 150 | if not isinstance(c, (list, tuple)) or len(c) != 2: |
… |
… |
def get_validation_errors(outfile, app=None):
|
141 | 158 | # Check if the on_delete behavior is sane |
142 | 159 | if f.rel and hasattr(f.rel, 'on_delete'): |
143 | 160 | if f.rel.on_delete == SET_NULL and not f.null: |
144 | | e.add(opts, "'%s' specifies on_delete=SET_NULL, but cannot be null." % f.name) |
| 161 | e.add(opts, "'%s' specifies on_delete=SET_NULL, " |
| 162 | "but cannot be null." % f.name) |
145 | 163 | elif f.rel.on_delete == SET_DEFAULT and not f.has_default(): |
146 | | e.add(opts, "'%s' specifies on_delete=SET_DEFAULT, but has no default value." % f.name) |
| 164 | e.add(opts, "'%s' specifies on_delete=SET_DEFAULT, " |
| 165 | "but has no default value." % f.name) |
147 | 166 | |
148 | | # Check to see if the related field will clash with any existing |
| 167 | # Check to see if the related field will clashing_field with any existing |
149 | 168 | # fields, m2m fields, m2m related objects or related objects |
150 | 169 | if f.rel: |
151 | 170 | if f.rel.to not in models.get_models(): |
152 | | e.add(opts, "'%s' has a relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to)) |
| 171 | e.add(opts, "'%s' has a relation with model %s, " |
| 172 | "which has either not been installed or is abstract." % ( |
| 173 | f.name, f.rel.to)) |
153 | 174 | # it is a string and we could not find the model it refers to |
154 | 175 | # so skip the next section |
155 | 176 | if isinstance(f.rel.to, (str, unicode)): |
… |
… |
def get_validation_errors(outfile, app=None):
|
157 | 178 | |
158 | 179 | # Make sure the related field specified by a ForeignKey is unique |
159 | 180 | if not f.rel.to._meta.get_field(f.rel.field_name).unique: |
160 | | e.add(opts, "Field '%s' under model '%s' must have a unique=True constraint." % (f.rel.field_name, f.rel.to.__name__)) |
| 181 | e.add(opts, "Field '%s' under model '%s' must have " |
| 182 | "a unique=True constraint." % ( |
| 183 | f.rel.field_name, f.rel.to.__name__)) |
161 | 184 | |
162 | 185 | rel_opts = f.rel.to._meta |
163 | 186 | rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() |
… |
… |
def get_validation_errors(outfile, app=None):
|
165 | 188 | if not f.rel.is_hidden(): |
166 | 189 | for r in rel_opts.fields: |
167 | 190 | if r.name == rel_name: |
168 | | e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 191 | e.add(opts, "Accessor for field '%s' clashes " |
| 192 | "with field '%s.%s'. Add a related_name argument " |
| 193 | "to the definition for '%s'." % ( |
| 194 | f.name, rel_opts.object_name, r.name, f.name)) |
169 | 195 | if r.name == rel_query_name: |
170 | | e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 196 | e.add(opts, "Reverse query name for field '%s' " |
| 197 | "clashes with field '%s.%s'. " |
| 198 | "Add a related_name argument " |
| 199 | "to the definition for '%s'." % ( |
| 200 | f.name, rel_opts.object_name, r.name, f.name)) |
171 | 201 | for r in rel_opts.local_many_to_many: |
172 | 202 | if r.name == rel_name: |
173 | | e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 203 | e.add(opts, "Accessor for field '%s' clashes " |
| 204 | "with m2m field '%s.%s'. Add a related_name argument " |
| 205 | "to the definition for '%s'." % ( |
| 206 | f.name, rel_opts.object_name, r.name, f.name)) |
174 | 207 | if r.name == rel_query_name: |
175 | | e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 208 | e.add(opts, "Reverse query name for field '%s' clashes " |
| 209 | "with m2m field '%s.%s'. Add a related_name argument " |
| 210 | "to the definition for '%s'." % ( |
| 211 | f.name, rel_opts.object_name, r.name, f.name)) |
176 | 212 | for r in rel_opts.get_all_related_many_to_many_objects(): |
177 | 213 | if r.get_accessor_name() == rel_name: |
178 | | e.add(opts, "Accessor for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 214 | e.add(opts, "Accessor for field '%s' clashes " |
| 215 | "with related m2m field '%s.%s'. " |
| 216 | "Add a related_name argument " |
| 217 | "to the definition for '%s'." % ( |
| 218 | f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
179 | 219 | if r.get_accessor_name() == rel_query_name: |
180 | | e.add(opts, "Reverse query name for field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 220 | e.add(opts, "Reverse query name for field '%s' clashes " |
| 221 | "with related m2m field '%s.%s'. " |
| 222 | "Add a related_name argument " |
| 223 | "to the definition for '%s'." % ( |
| 224 | f.name, rel_opts.object_name, |
| 225 | r.get_accessor_name(), f.name)) |
181 | 226 | for r in rel_opts.get_all_related_objects(): |
182 | 227 | if r.field is not f: |
183 | 228 | if r.get_accessor_name() == rel_name: |
184 | | e.add(opts, "Accessor for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 229 | e.add(opts, "Accessor for field '%s' clashes " |
| 230 | "with related field '%s.%s'. " |
| 231 | "Add a related_name argument " |
| 232 | "to the definition for '%s'." % ( |
| 233 | f.name, rel_opts.object_name, |
| 234 | r.get_accessor_name(), f.name)) |
185 | 235 | if r.get_accessor_name() == rel_query_name: |
186 | | e.add(opts, "Reverse query name for field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 236 | e.add(opts, "Reverse query name for field '%s' " |
| 237 | "clashes with related field '%s.%s'. " |
| 238 | "Add a related_name argument " |
| 239 | "to the definition for '%s'." % ( |
| 240 | f.name, rel_opts.object_name, |
| 241 | r.get_accessor_name(), f.name)) |
187 | 242 | |
188 | 243 | seen_intermediary_signatures = [] |
189 | 244 | for i, f in enumerate(opts.local_many_to_many): |
190 | | # Check to see if the related m2m field will clash with any |
| 245 | # Check to see if the related m2m field will clashing_field with any |
191 | 246 | # existing fields, m2m fields, m2m related objects or related |
192 | 247 | # objects |
193 | 248 | if f.rel.to not in models.get_models(): |
194 | | e.add(opts, "'%s' has an m2m relation with model %s, which has either not been installed or is abstract." % (f.name, f.rel.to)) |
| 249 | e.add(opts, "'%s' has an m2m relation with model %s, " |
| 250 | "which has either not been installed or is abstract." % ( |
| 251 | f.name, f.rel.to)) |
195 | 252 | # it is a string and we could not find the model it refers to |
196 | 253 | # so skip the next section |
197 | 254 | if isinstance(f.rel.to, (str, unicode)): |
… |
… |
def get_validation_errors(outfile, app=None):
|
199 | 256 | |
200 | 257 | # Check that the field is not set to unique. ManyToManyFields do not support unique. |
201 | 258 | if f.unique: |
202 | | e.add(opts, "ManyToManyFields cannot be unique. Remove the unique argument on '%s'." % f.name) |
| 259 | e.add(opts, "ManyToManyFields cannot be unique. " |
| 260 | "Remove the unique argument on '%s'." % f.name) |
203 | 261 | |
204 | 262 | if f.rel.through is not None and not isinstance(f.rel.through, basestring): |
205 | 263 | from_model, to_model = cls, f.rel.to |
206 | | if from_model == to_model and f.rel.symmetrical and not f.rel.through._meta.auto_created: |
207 | | e.add(opts, "Many-to-many fields with intermediate tables cannot be symmetrical.") |
| 264 | if (from_model == to_model and |
| 265 | f.rel.symmetrical and |
| 266 | not f.rel.through._meta.auto_created): |
| 267 | e.add(opts, "Many-to-many fields with intermediate tables " |
| 268 | "cannot be symmetrical.") |
208 | 269 | seen_from, seen_to, seen_self = False, False, 0 |
209 | 270 | for inter_field in f.rel.through._meta.fields: |
210 | 271 | rel_to = getattr(inter_field.rel, 'to', None) |
… |
… |
def get_validation_errors(outfile, app=None):
|
213 | 274 | seen_self += 1 |
214 | 275 | if seen_self > 2: |
215 | 276 | e.add(opts, "Intermediary model %s has more than " |
216 | | "two foreign keys to %s, which is ambiguous " |
217 | | "and is not permitted." % ( |
218 | | f.rel.through._meta.object_name, |
219 | | from_model._meta.object_name |
220 | | ) |
221 | | ) |
| 277 | "two foreign keys to %s, which is ambiguous " |
| 278 | "and is not permitted." % ( |
| 279 | f.rel.through._meta.object_name, |
| 280 | from_model._meta.object_name)) |
222 | 281 | else: |
223 | 282 | if rel_to == from_model: |
224 | 283 | if seen_from: |
225 | 284 | e.add(opts, "Intermediary model %s has more " |
226 | | "than one foreign key to %s, which is " |
227 | | "ambiguous and is not permitted." % ( |
228 | | f.rel.through._meta.object_name, |
229 | | from_model._meta.object_name |
230 | | ) |
231 | | ) |
| 285 | "than one foreign key to %s, which is " |
| 286 | "ambiguous and is not permitted." % ( |
| 287 | f.rel.through._meta.object_name, |
| 288 | from_model._meta.object_name)) |
232 | 289 | else: |
233 | 290 | seen_from = True |
234 | 291 | elif rel_to == to_model: |
235 | 292 | if seen_to: |
236 | 293 | e.add(opts, "Intermediary model %s has more " |
237 | | "than one foreign key to %s, which is " |
238 | | "ambiguous and is not permitted." % ( |
239 | | f.rel.through._meta.object_name, |
240 | | rel_to._meta.object_name |
241 | | ) |
242 | | ) |
| 294 | "than one foreign key to %s, which is " |
| 295 | "ambiguous and is not permitted." % ( |
| 296 | f.rel.through._meta.object_name, |
| 297 | rel_to._meta.object_name)) |
243 | 298 | else: |
244 | 299 | seen_to = True |
245 | 300 | if f.rel.through not in models.get_models(include_auto_created=True): |
246 | 301 | e.add(opts, "'%s' specifies an m2m relation through model " |
247 | | "%s, which has not been installed." % (f.name, f.rel.through) |
248 | | ) |
| 302 | "%s, which has not been installed." % ( |
| 303 | f.name, f.rel.through)) |
249 | 304 | signature = (f.rel.to, cls, f.rel.through) |
250 | 305 | if signature in seen_intermediary_signatures: |
251 | 306 | e.add(opts, "The model %s has two manually-defined m2m " |
252 | | "relations through the model %s, which is not " |
253 | | "permitted. Please consider using an extra field on " |
254 | | "your intermediary model instead." % ( |
255 | | cls._meta.object_name, |
256 | | f.rel.through._meta.object_name |
257 | | ) |
258 | | ) |
| 307 | "relations through the model %s, which is not " |
| 308 | "permitted. Please consider using an extra field on " |
| 309 | "your intermediary model instead." % ( |
| 310 | cls._meta.object_name, |
| 311 | f.rel.through._meta.object_name)) |
259 | 312 | else: |
260 | 313 | seen_intermediary_signatures.append(signature) |
261 | 314 | if not f.rel.through._meta.auto_created: |
… |
… |
def get_validation_errors(outfile, app=None):
|
268 | 321 | seen_this_fk = True |
269 | 322 | if not seen_related_fk or not seen_this_fk: |
270 | 323 | e.add(opts, "'%s' is a manually-defined m2m relation " |
271 | | "through model %s, which does not have foreign keys " |
272 | | "to %s and %s" % (f.name, f.rel.through._meta.object_name, |
273 | | f.rel.to._meta.object_name, cls._meta.object_name) |
274 | | ) |
| 324 | "through model %s, which does not have foreign keys " |
| 325 | "to %s and %s" % ( |
| 326 | f.name, f.rel.through._meta.object_name, |
| 327 | f.rel.to._meta.object_name, cls._meta.object_name)) |
275 | 328 | elif isinstance(f.rel.through, basestring): |
276 | 329 | e.add(opts, "'%s' specifies an m2m relation through model %s, " |
277 | | "which has not been installed" % (f.name, f.rel.through) |
278 | | ) |
| 330 | "which has not been installed" % (f.name, f.rel.through)) |
279 | 331 | |
280 | 332 | rel_opts = f.rel.to._meta |
281 | 333 | rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() |
… |
… |
def get_validation_errors(outfile, app=None):
|
287 | 339 | if rel_name is not None: |
288 | 340 | for r in rel_opts.fields: |
289 | 341 | if r.name == rel_name: |
290 | | e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 342 | e.add(opts, "Accessor for m2m field '%s' clashes " |
| 343 | "with field '%s.%s'. Add a related_name " |
| 344 | "argument to the definition for '%s'." % ( |
| 345 | f.name, rel_opts.object_name, r.name, f.name)) |
291 | 346 | if r.name == rel_query_name: |
292 | | e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 347 | e.add(opts, "Reverse query name for m2m field '%s' " |
| 348 | "clashes with field '%s.%s'. " |
| 349 | "Add a related_name argument " |
| 350 | "to the definition for '%s'." % ( |
| 351 | f.name, rel_opts.object_name, |
| 352 | r.name, f.name)) |
293 | 353 | for r in rel_opts.local_many_to_many: |
294 | 354 | if r.name == rel_name: |
295 | | e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 355 | e.add(opts, "Accessor for m2m field '%s' clashes " |
| 356 | "with m2m field '%s.%s'. Add a related_name " |
| 357 | "argument to the definition for '%s'." % ( |
| 358 | f.name, rel_opts.object_name, |
| 359 | r.name, f.name)) |
296 | 360 | if r.name == rel_query_name: |
297 | | e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) |
| 361 | e.add(opts, "Reverse query name for m2m field '%s' " |
| 362 | "clashes with m2m field '%s.%s'. " |
| 363 | "Add a related_name argument " |
| 364 | "to the definition for '%s'." % ( |
| 365 | f.name, rel_opts.object_name, |
| 366 | r.name, f.name)) |
298 | 367 | for r in rel_opts.get_all_related_many_to_many_objects(): |
299 | 368 | if r.field is not f: |
300 | 369 | if r.get_accessor_name() == rel_name: |
301 | | e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 370 | e.add(opts, "Accessor for m2m field '%s' clashes " |
| 371 | "with related m2m field '%s.%s'. " |
| 372 | "Add a related_name argument " |
| 373 | "to the definition for '%s'." % ( |
| 374 | f.name, rel_opts.object_name, |
| 375 | r.get_accessor_name(), f.name)) |
302 | 376 | if r.get_accessor_name() == rel_query_name: |
303 | | e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 377 | e.add(opts, "Reverse query name for m2m field '%s' " |
| 378 | "clashes with related m2m field '%s.%s'. " |
| 379 | "Add a related_name argument " |
| 380 | "to the definition for '%s'." % ( |
| 381 | f.name, rel_opts.object_name, |
| 382 | r.get_accessor_name(), f.name)) |
304 | 383 | for r in rel_opts.get_all_related_objects(): |
305 | 384 | if r.get_accessor_name() == rel_name: |
306 | | e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 385 | e.add(opts, "Accessor for m2m field '%s' clashes " |
| 386 | "with related field '%s.%s'. " |
| 387 | "Add a related_name argument " |
| 388 | "to the definition for '%s'." % ( |
| 389 | f.name, rel_opts.object_name, |
| 390 | r.get_accessor_name(), f.name)) |
307 | 391 | if r.get_accessor_name() == rel_query_name: |
308 | | e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
| 392 | e.add(opts, "Reverse query name for m2m field '%s' " |
| 393 | "clashes with related field '%s.%s'. " |
| 394 | "Add a related_name argument " |
| 395 | "to the definition for '%s'." % ( |
| 396 | f.name, rel_opts.object_name, |
| 397 | r.get_accessor_name(), f.name)) |
309 | 398 | |
310 | 399 | # Check ordering attribute. |
311 | 400 | if opts.ordering: |
… |
… |
def get_validation_errors(outfile, app=None):
|
327 | 416 | try: |
328 | 417 | opts.get_field(field_name, many_to_many=False) |
329 | 418 | except models.FieldDoesNotExist: |
330 | | e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) |
| 419 | e.add(opts, '"ordering" refers to "%s", ' |
| 420 | 'a field that doesn\'t exist.' % field_name) |
331 | 421 | |
332 | 422 | # Check unique_together. |
333 | 423 | for ut in opts.unique_together: |
… |
… |
def get_validation_errors(outfile, app=None):
|
335 | 425 | try: |
336 | 426 | f = opts.get_field(field_name, many_to_many=True) |
337 | 427 | except models.FieldDoesNotExist: |
338 | | e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name) |
| 428 | e.add(opts, '"unique_together" refers to %s, ' |
| 429 | 'a field that doesn\'t exist. ' |
| 430 | 'Check your syntax.' % field_name) |
339 | 431 | else: |
340 | 432 | if isinstance(f.rel, models.ManyToManyRel): |
341 | | e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name) |
| 433 | e.add(opts, '"unique_together" refers to %s. ' |
| 434 | 'ManyToManyFields are not supported ' |
| 435 | 'in unique_together.' % f.name) |
342 | 436 | if f not in opts.local_fields: |
343 | | e.add(opts, '"unique_together" refers to %s. This is not in the same model as the unique_together statement.' % f.name) |
| 437 | e.add(opts, '"unique_together" refers to %s. ' |
| 438 | 'This is not in the same model ' |
| 439 | 'as the unique_together statement.' % f.name) |
344 | 440 | |
345 | 441 | return len(e.errors) |