Loading django/core/checks/model_checks.py +2 −2 Original line number Diff line number Diff line Loading @@ -36,14 +36,14 @@ def check_model_signals(app_configs=None, **kwargs): description = "An instance of the `%s` class" % receiver.__class__.__name__ errors.append( Error( "%s was connected to the `%s` signal " "%s was connected to the '%s' signal " "with a lazy reference to the '%s' sender, " "which has not been installed." % ( description, name, '.'.join(reference) ), obj=receiver.__module__, hint=None, id='E014' id='signals.E001' ) ) return errors django/db/models/fields/__init__.py +55 −53 Original line number Diff line number Diff line Loading @@ -197,10 +197,10 @@ class Field(RegisterLookupMixin): if self.name.endswith('_'): return [ checks.Error( 'Field names must not end with underscores.', 'Field names must not end with an underscore.', hint=None, obj=self, id='E001', id='fields.E001', ) ] elif '__' in self.name: Loading @@ -209,16 +209,16 @@ class Field(RegisterLookupMixin): 'Field names must not contain "__".', hint=None, obj=self, id='E052', id='fields.E002', ) ] elif self.name == 'pk': return [ checks.Error( 'Cannot use "pk" as a field name since it is a reserved name.', "'pk' is a reserved word that cannot be used as a field name.", hint=None, obj=self, id='E051', id='fields.E003', ) ] else: Loading @@ -230,10 +230,10 @@ class Field(RegisterLookupMixin): not is_iterable(self.choices)): return [ checks.Error( '"choices" must be an iterable (e.g., a list or tuple).', "'choices' must be an iterable (e.g., a list or tuple).", hint=None, obj=self, id='E033', id='fields.E004', ) ] elif any(isinstance(choice, six.string_types) or Loading @@ -241,13 +241,11 @@ class Field(RegisterLookupMixin): for choice in self.choices): return [ checks.Error( ('All "choices" elements must be a tuple of two ' 'elements (the first one is the actual value ' 'to be stored and the second element is ' 'the human-readable name).'), ("'choices' must be an iterable containing " "(actual value, human readable name) tuples."), hint=None, obj=self, id='E034', id='fields.E005', ) ] else: Loading @@ -259,10 +257,10 @@ class Field(RegisterLookupMixin): if self.db_index not in (None, True, False): return [ checks.Error( '"db_index" must be either None, True or False.', "'db_index' must be None, True or False.", hint=None, obj=self, id='E035', id='fields.E006', ) ] else: Loading @@ -277,10 +275,10 @@ class Field(RegisterLookupMixin): return [ checks.Error( 'Primary keys must not have null=True.', hint=('Set null=False on the field or ' hint=('Set null=False on the field, or ' 'remove primary_key=True argument.'), obj=self, id='E036', id='fields.E007', ) ] else: Loading Loading @@ -864,10 +862,10 @@ class AutoField(Field): if not self.primary_key: return [ checks.Error( 'The field must have primary_key=True, because it is an AutoField.', 'AutoFields must set primary_key=True.', hint=None, obj=self, id='E048', id='fields.E100', ), ] else: Loading Loading @@ -940,10 +938,10 @@ class BooleanField(Field): if getattr(self, 'null', False): return [ checks.Error( 'BooleanFields do not acceps null values.', 'BooleanFields do not accept null values.', hint='Use a NullBooleanField instead.', obj=self, id='E037', id='fields.E110', ) ] else: Loading Loading @@ -1020,19 +1018,19 @@ class CharField(Field): except TypeError: return [ checks.Error( 'The field must have "max_length" attribute.', "CharFields must define a 'max_length' attribute.", hint=None, obj=self, id='E038', id='fields.E120', ) ] except ValueError: return [ checks.Error( '"max_length" must be a positive integer.', "'max_length' must be a positive integer.", hint=None, obj=self, id='E039', id='fields.E121', ) ] else: Loading Loading @@ -1305,24 +1303,16 @@ class DecimalField(Field): def check(self, **kwargs): errors = super(DecimalField, self).check(**kwargs) errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) return errors def _check_decimal_places_and_max_digits(self, **kwargs): errors = self.__check_decimal_places() errors += self.__check_max_digits() if not errors and int(self.decimal_places) > int(self.max_digits): errors.append( checks.Error( '"max_digits" must be greater or equal to "decimal_places".', hint=None, obj=self, id='E040', ) ) digits_errors = self._check_decimal_places() digits_errors.extend(self._check_max_digits()) if not digits_errors: errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) else: errors.extend(digits_errors) return errors def __check_decimal_places(self): def _check_decimal_places(self): try: decimal_places = int(self.decimal_places) if decimal_places < 0: Loading @@ -1330,25 +1320,25 @@ class DecimalField(Field): except TypeError: return [ checks.Error( 'The field requires a "decimal_places" attribute.', "DecimalFields must define a 'decimal_places' attribute.", hint=None, obj=self, id='E041', id='fields.E130', ) ] except ValueError: return [ checks.Error( '"decimal_places" attribute must be a non-negative integer.', "'decimal_places' must be a non-negative integer.", hint=None, obj=self, id='E042', id='fields.E131', ) ] else: return [] def __check_max_digits(self): def _check_max_digits(self): try: max_digits = int(self.max_digits) if max_digits <= 0: Loading @@ -1356,24 +1346,36 @@ class DecimalField(Field): except TypeError: return [ checks.Error( 'The field requires a "max_digits" attribute.', "DecimalFields must define a 'max_digits' attribute.", hint=None, obj=self, id='E043', id='fields.E132', ) ] except ValueError: return [ checks.Error( '"max_digits" attribute must be a positive integer.', "'max_digits' must be a positive integer.", hint=None, obj=self, id='E044', id='fields.E133', ) ] else: return [] def _check_decimal_places_and_max_digits(self, **kwargs): if int(self.decimal_places) > int(self.max_digits): return [ checks.Error( "'max_digits' must be greater or equal to 'decimal_places'.", hint=None, obj=self, id='fields.E134', ) ] return [] def deconstruct(self): name, path, args, kwargs = super(DecimalField, self).deconstruct() if self.max_digits: Loading Loading @@ -1481,10 +1483,10 @@ class FilePathField(Field): if not self.allow_files and not self.allow_folders: return [ checks.Error( 'The field must have either "allow_files" or "allow_folders" set to True.', "FilePathFields must have either 'allow_files' or 'allow_folders' set to True.", hint=None, obj=self, id='E045', id='fields.E140', ) ] return [] Loading Loading @@ -1659,11 +1661,11 @@ class GenericIPAddressField(Field): if not getattr(self, 'null', False) and getattr(self, 'blank', False): return [ checks.Error( ('The field cannot accept blank values if null values ' 'are not allowed, as blank values are stored as null.'), ('GenericIPAddressFields cannot have blank=True if null=False, ' 'as blank values are stored as nulls.'), hint=None, obj=self, id='E046', id='fields.E150', ) ] return [] Loading django/db/models/fields/files.py +6 −6 Original line number Diff line number Diff line Loading @@ -246,10 +246,10 @@ class FileField(Field): if self._unique_set_explicitly: return [ checks.Error( '"unique" is not a valid argument for %s.' % self.__class__.__name__, "'unique' is not a valid argument for a %s." % self.__class__.__name__, hint=None, obj=self, id='E049', id='fields.E200', ) ] else: Loading @@ -259,10 +259,10 @@ class FileField(Field): if self._primary_key_set_explicitly: return [ checks.Error( '"primary_key" is not a valid argument for %s.' % self.__class__.__name__, "'primary_key' is not a valid argument for a %s." % self.__class__.__name__, hint=None, obj=self, id='E050', id='fields.E201', ) ] else: Loading Loading @@ -392,11 +392,11 @@ class ImageField(FileField): except ImproperlyConfigured: return [ checks.Error( 'To use ImageFields, Pillow must be installed.', 'Cannot use ImageField because Pillow is not installed.', hint=('Get Pillow at https://pypi.python.org/pypi/Pillow ' 'or run command "pip install pillow".'), obj=self, id='E032', id='fields.E210', ) ] else: Loading django/db/models/fields/related.py +59 −65 Original line number Diff line number Diff line Loading @@ -108,13 +108,11 @@ class RelatedField(Field): if rel_is_missing and (rel_is_string or not self.rel.to._meta.swapped): return [ checks.Error( ('The field has a relation with model %s, which ' 'has either not been installed or is abstract.') % model_name, hint=('Ensure that you did not misspell the model name and ' 'the model is not abstract. Does your INSTALLED_APPS ' 'setting contain the app where %s is defined?') % model_name, ("Field defines a relation with model '%s', which " "is either not installed, or is abstract.") % model_name, hint=None, obj=self, id='E030', id='fields.E300', ) ] return [] Loading @@ -129,11 +127,11 @@ class RelatedField(Field): ) return [ checks.Error( ('The field defines a relation with the model %s, ' 'which has been swapped out.') % model, hint='Update the relation to point at settings.%s' % self.rel.to._meta.swappable, ("Field defines a relation with the model '%s', " "which has been swapped out.") % model, hint="Update the relation to point at 'settings.%s'." % self.rel.to._meta.swappable, obj=self, id='E029', id='fields.E301', ) ] return [] Loading Loading @@ -190,22 +188,22 @@ class RelatedField(Field): if clash_field.name == rel_name: errors.append( checks.Error( 'Accessor for field %s clashes with field %s.' % (field_name, clash_name), hint=('Rename field %s or add/change a related_name ' 'argument to the definition for field %s.') % (clash_name, field_name), "Reverse accessor for '%s' clashes with field name '%s'." % (field_name, clash_name), hint=("Rename field '%s', or add/change a related_name " "argument to the definition for field '%s'.") % (clash_name, field_name), obj=self, id='E014', id='fields.E302', ) ) if clash_field.name == rel_query_name: errors.append( checks.Error( 'Reverse query name for field %s clashes with field %s.' % (field_name, clash_name), hint=('Rename field %s or add/change a related_name ' 'argument to the definition for field %s.') % (clash_name, field_name), "Reverse query name for '%s' clashes with field name '%s'." % (field_name, clash_name), hint=("Rename field '%s', or add/change a related_name " "argument to the definition for field '%s'.") % (clash_name, field_name), obj=self, id='E015', id='fields.E303', ) ) Loading @@ -223,22 +221,22 @@ class RelatedField(Field): if clash_field.get_accessor_name() == rel_name: errors.append( checks.Error( 'Clash between accessors for %s and %s.' % (field_name, clash_name), hint=('Add or change a related_name argument ' 'to the definition for %s or %s.') % (field_name, clash_name), "Reverse accessor for '%s' clashes with reverse accessor for '%s'." % (field_name, clash_name), hint=("Add or change a related_name argument " "to the definition for '%s' or '%s'.") % (field_name, clash_name), obj=self, id='E016', id='fields.E304', ) ) if clash_field.get_accessor_name() == rel_query_name: errors.append( checks.Error( 'Clash between reverse query names for %s and %s.' % (field_name, clash_name), hint=('Add or change a related_name argument ' 'to the definition for %s or %s.') % (field_name, clash_name), "Reverse query name for '%s' clashes with reverse query name for '%s'." % (field_name, clash_name), hint=("Add or change a related_name argument " "to the definition for '%s' or '%s'.") % (field_name, clash_name), obj=self, id='E017', id='fields.E305', ) ) Loading Loading @@ -1317,17 +1315,15 @@ class ForeignObject(RelatedField): has_unique_field = any(rel_field.unique for rel_field in self.foreign_related_fields) if not has_unique_field and len(self.foreign_related_fields) > 1: field_combination = ','.join(rel_field.name field_combination = ', '.join("'%s'" % rel_field.name for rel_field in self.foreign_related_fields) model_name = self.rel.to.__name__ return [ checks.Error( ('No unique=True constraint ' 'on field combination "%s" under model %s.') % (field_combination, model_name), hint=('Set unique=True argument on any of the fields ' '"%s" under model %s.') % (field_combination, model_name), "None of the fields %s on model '%s' have a unique=True constraint." % (field_combination, model_name), hint=None, obj=self, id='E018', id='fields.E310', ) ] elif not has_unique_field: Loading @@ -1335,11 +1331,11 @@ class ForeignObject(RelatedField): model_name = self.rel.to.__name__ return [ checks.Error( ('%s.%s must have unique=True ' 'because it is referenced by a foreign key.') % (model_name, field_name), ("'%s.%s' must set unique=True " "because it is referenced by a foreign key.") % (model_name, field_name), hint=None, obj=self, id='E019', id='fields.E311', ) ] else: Loading Loading @@ -1605,19 +1601,19 @@ class ForeignKey(ForeignObject): if on_delete == SET_NULL and not self.null: return [ checks.Error( 'The field specifies on_delete=SET_NULL, but cannot be null.', hint='Set null=True argument on the field.', 'Field specifies on_delete=SET_NULL, but cannot be null.', hint='Set null=True argument on the field, or change the on_delete rule.', obj=self, id='E020', id='fields.E320', ) ] elif on_delete == SET_DEFAULT and not self.has_default(): return [ checks.Error( 'The field specifies on_delete=SET_DEFAULT, but has no default value.', hint=None, 'Field specifies on_delete=SET_DEFAULT, but has no default value.', hint='Set a default value, or change the on_delete rule.', obj=self, id='E021', id='fields.E321', ) ] else: Loading Loading @@ -1864,10 +1860,10 @@ class ManyToManyField(RelatedField): if self.unique: return [ checks.Error( 'ManyToManyFields must not be unique.', 'ManyToManyFields cannot be unique.', hint=None, obj=self, id='E022', id='fields.E330', ) ] return [] Loading @@ -1879,13 +1875,11 @@ class ManyToManyField(RelatedField): # The relationship model is not installed. errors.append( checks.Error( ('The field specifies a many-to-many relation through model ' '%s, which has not been installed.') % self.rel.through, hint=('Ensure that you did not misspell the model name and ' 'the model is not abstract. Does your INSTALLED_APPS ' 'setting contain the app where %s is defined?') % self.rel.through, ("Field specifies a many-to-many relation through model " "'%s', which has not been installed.") % self.rel.through, hint=None, obj=self, id='E023', id='fields.E331', ) ) Loading Loading @@ -1914,7 +1908,7 @@ class ManyToManyField(RelatedField): 'Many-to-many fields with intermediate tables must not be symmetrical.', hint=None, obj=self, id='E024', id='fields.E332', ) ) Loading @@ -1926,12 +1920,12 @@ class ManyToManyField(RelatedField): if seen_self > 2: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than two foreign keys ' 'to %s, which is ambiguous and is not permitted.') % (self, from_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than two foreign keys " "to '%s', which is ambiguous.") % (self, from_model_name), hint=None, obj=self.rel.through, id='E025', id='fields.E333', ) ) Loading @@ -1945,41 +1939,41 @@ class ManyToManyField(RelatedField): if seen_from > 1: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than one foreign key ' 'to %s, which is ambiguous and is not permitted.') % (self, from_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than one foreign key " "from '%s', which is ambiguous.") % (self, from_model_name), hint=('If you want to create a recursive relationship, ' 'use ForeignKey("self", symmetrical=False, ' 'through="%s").') % relationship_model_name, obj=self, id='E026', id='fields.E334', ) ) if seen_to > 1: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than one foreign key ' 'to %s, which is ambiguous and is not permitted.') % (self, to_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than one foreign key " "to '%s', which is ambiguous.") % (self, to_model_name), hint=('If you want to create a recursive ' 'relationship, use ForeignKey("self", ' 'symmetrical=False, through="%s").') % relationship_model_name, obj=self, id='E027', id='fields.E335', ) ) if seen_from == 0 or seen_to == 0: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it misses a foreign key to %s or %s.') % ( ("The model is used as an intermediate model by " "'%s', but it does not have a foreign key to '%s' or '%s'.") % ( self, from_model_name, to_model_name ), hint=None, obj=self.rel.through, id='E028', id='fields.E336', ) ) return errors Loading tests/contenttypes_tests/tests.py +11 −13 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
django/core/checks/model_checks.py +2 −2 Original line number Diff line number Diff line Loading @@ -36,14 +36,14 @@ def check_model_signals(app_configs=None, **kwargs): description = "An instance of the `%s` class" % receiver.__class__.__name__ errors.append( Error( "%s was connected to the `%s` signal " "%s was connected to the '%s' signal " "with a lazy reference to the '%s' sender, " "which has not been installed." % ( description, name, '.'.join(reference) ), obj=receiver.__module__, hint=None, id='E014' id='signals.E001' ) ) return errors
django/db/models/fields/__init__.py +55 −53 Original line number Diff line number Diff line Loading @@ -197,10 +197,10 @@ class Field(RegisterLookupMixin): if self.name.endswith('_'): return [ checks.Error( 'Field names must not end with underscores.', 'Field names must not end with an underscore.', hint=None, obj=self, id='E001', id='fields.E001', ) ] elif '__' in self.name: Loading @@ -209,16 +209,16 @@ class Field(RegisterLookupMixin): 'Field names must not contain "__".', hint=None, obj=self, id='E052', id='fields.E002', ) ] elif self.name == 'pk': return [ checks.Error( 'Cannot use "pk" as a field name since it is a reserved name.', "'pk' is a reserved word that cannot be used as a field name.", hint=None, obj=self, id='E051', id='fields.E003', ) ] else: Loading @@ -230,10 +230,10 @@ class Field(RegisterLookupMixin): not is_iterable(self.choices)): return [ checks.Error( '"choices" must be an iterable (e.g., a list or tuple).', "'choices' must be an iterable (e.g., a list or tuple).", hint=None, obj=self, id='E033', id='fields.E004', ) ] elif any(isinstance(choice, six.string_types) or Loading @@ -241,13 +241,11 @@ class Field(RegisterLookupMixin): for choice in self.choices): return [ checks.Error( ('All "choices" elements must be a tuple of two ' 'elements (the first one is the actual value ' 'to be stored and the second element is ' 'the human-readable name).'), ("'choices' must be an iterable containing " "(actual value, human readable name) tuples."), hint=None, obj=self, id='E034', id='fields.E005', ) ] else: Loading @@ -259,10 +257,10 @@ class Field(RegisterLookupMixin): if self.db_index not in (None, True, False): return [ checks.Error( '"db_index" must be either None, True or False.', "'db_index' must be None, True or False.", hint=None, obj=self, id='E035', id='fields.E006', ) ] else: Loading @@ -277,10 +275,10 @@ class Field(RegisterLookupMixin): return [ checks.Error( 'Primary keys must not have null=True.', hint=('Set null=False on the field or ' hint=('Set null=False on the field, or ' 'remove primary_key=True argument.'), obj=self, id='E036', id='fields.E007', ) ] else: Loading Loading @@ -864,10 +862,10 @@ class AutoField(Field): if not self.primary_key: return [ checks.Error( 'The field must have primary_key=True, because it is an AutoField.', 'AutoFields must set primary_key=True.', hint=None, obj=self, id='E048', id='fields.E100', ), ] else: Loading Loading @@ -940,10 +938,10 @@ class BooleanField(Field): if getattr(self, 'null', False): return [ checks.Error( 'BooleanFields do not acceps null values.', 'BooleanFields do not accept null values.', hint='Use a NullBooleanField instead.', obj=self, id='E037', id='fields.E110', ) ] else: Loading Loading @@ -1020,19 +1018,19 @@ class CharField(Field): except TypeError: return [ checks.Error( 'The field must have "max_length" attribute.', "CharFields must define a 'max_length' attribute.", hint=None, obj=self, id='E038', id='fields.E120', ) ] except ValueError: return [ checks.Error( '"max_length" must be a positive integer.', "'max_length' must be a positive integer.", hint=None, obj=self, id='E039', id='fields.E121', ) ] else: Loading Loading @@ -1305,24 +1303,16 @@ class DecimalField(Field): def check(self, **kwargs): errors = super(DecimalField, self).check(**kwargs) errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) return errors def _check_decimal_places_and_max_digits(self, **kwargs): errors = self.__check_decimal_places() errors += self.__check_max_digits() if not errors and int(self.decimal_places) > int(self.max_digits): errors.append( checks.Error( '"max_digits" must be greater or equal to "decimal_places".', hint=None, obj=self, id='E040', ) ) digits_errors = self._check_decimal_places() digits_errors.extend(self._check_max_digits()) if not digits_errors: errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) else: errors.extend(digits_errors) return errors def __check_decimal_places(self): def _check_decimal_places(self): try: decimal_places = int(self.decimal_places) if decimal_places < 0: Loading @@ -1330,25 +1320,25 @@ class DecimalField(Field): except TypeError: return [ checks.Error( 'The field requires a "decimal_places" attribute.', "DecimalFields must define a 'decimal_places' attribute.", hint=None, obj=self, id='E041', id='fields.E130', ) ] except ValueError: return [ checks.Error( '"decimal_places" attribute must be a non-negative integer.', "'decimal_places' must be a non-negative integer.", hint=None, obj=self, id='E042', id='fields.E131', ) ] else: return [] def __check_max_digits(self): def _check_max_digits(self): try: max_digits = int(self.max_digits) if max_digits <= 0: Loading @@ -1356,24 +1346,36 @@ class DecimalField(Field): except TypeError: return [ checks.Error( 'The field requires a "max_digits" attribute.', "DecimalFields must define a 'max_digits' attribute.", hint=None, obj=self, id='E043', id='fields.E132', ) ] except ValueError: return [ checks.Error( '"max_digits" attribute must be a positive integer.', "'max_digits' must be a positive integer.", hint=None, obj=self, id='E044', id='fields.E133', ) ] else: return [] def _check_decimal_places_and_max_digits(self, **kwargs): if int(self.decimal_places) > int(self.max_digits): return [ checks.Error( "'max_digits' must be greater or equal to 'decimal_places'.", hint=None, obj=self, id='fields.E134', ) ] return [] def deconstruct(self): name, path, args, kwargs = super(DecimalField, self).deconstruct() if self.max_digits: Loading Loading @@ -1481,10 +1483,10 @@ class FilePathField(Field): if not self.allow_files and not self.allow_folders: return [ checks.Error( 'The field must have either "allow_files" or "allow_folders" set to True.', "FilePathFields must have either 'allow_files' or 'allow_folders' set to True.", hint=None, obj=self, id='E045', id='fields.E140', ) ] return [] Loading Loading @@ -1659,11 +1661,11 @@ class GenericIPAddressField(Field): if not getattr(self, 'null', False) and getattr(self, 'blank', False): return [ checks.Error( ('The field cannot accept blank values if null values ' 'are not allowed, as blank values are stored as null.'), ('GenericIPAddressFields cannot have blank=True if null=False, ' 'as blank values are stored as nulls.'), hint=None, obj=self, id='E046', id='fields.E150', ) ] return [] Loading
django/db/models/fields/files.py +6 −6 Original line number Diff line number Diff line Loading @@ -246,10 +246,10 @@ class FileField(Field): if self._unique_set_explicitly: return [ checks.Error( '"unique" is not a valid argument for %s.' % self.__class__.__name__, "'unique' is not a valid argument for a %s." % self.__class__.__name__, hint=None, obj=self, id='E049', id='fields.E200', ) ] else: Loading @@ -259,10 +259,10 @@ class FileField(Field): if self._primary_key_set_explicitly: return [ checks.Error( '"primary_key" is not a valid argument for %s.' % self.__class__.__name__, "'primary_key' is not a valid argument for a %s." % self.__class__.__name__, hint=None, obj=self, id='E050', id='fields.E201', ) ] else: Loading Loading @@ -392,11 +392,11 @@ class ImageField(FileField): except ImproperlyConfigured: return [ checks.Error( 'To use ImageFields, Pillow must be installed.', 'Cannot use ImageField because Pillow is not installed.', hint=('Get Pillow at https://pypi.python.org/pypi/Pillow ' 'or run command "pip install pillow".'), obj=self, id='E032', id='fields.E210', ) ] else: Loading
django/db/models/fields/related.py +59 −65 Original line number Diff line number Diff line Loading @@ -108,13 +108,11 @@ class RelatedField(Field): if rel_is_missing and (rel_is_string or not self.rel.to._meta.swapped): return [ checks.Error( ('The field has a relation with model %s, which ' 'has either not been installed or is abstract.') % model_name, hint=('Ensure that you did not misspell the model name and ' 'the model is not abstract. Does your INSTALLED_APPS ' 'setting contain the app where %s is defined?') % model_name, ("Field defines a relation with model '%s', which " "is either not installed, or is abstract.") % model_name, hint=None, obj=self, id='E030', id='fields.E300', ) ] return [] Loading @@ -129,11 +127,11 @@ class RelatedField(Field): ) return [ checks.Error( ('The field defines a relation with the model %s, ' 'which has been swapped out.') % model, hint='Update the relation to point at settings.%s' % self.rel.to._meta.swappable, ("Field defines a relation with the model '%s', " "which has been swapped out.") % model, hint="Update the relation to point at 'settings.%s'." % self.rel.to._meta.swappable, obj=self, id='E029', id='fields.E301', ) ] return [] Loading Loading @@ -190,22 +188,22 @@ class RelatedField(Field): if clash_field.name == rel_name: errors.append( checks.Error( 'Accessor for field %s clashes with field %s.' % (field_name, clash_name), hint=('Rename field %s or add/change a related_name ' 'argument to the definition for field %s.') % (clash_name, field_name), "Reverse accessor for '%s' clashes with field name '%s'." % (field_name, clash_name), hint=("Rename field '%s', or add/change a related_name " "argument to the definition for field '%s'.") % (clash_name, field_name), obj=self, id='E014', id='fields.E302', ) ) if clash_field.name == rel_query_name: errors.append( checks.Error( 'Reverse query name for field %s clashes with field %s.' % (field_name, clash_name), hint=('Rename field %s or add/change a related_name ' 'argument to the definition for field %s.') % (clash_name, field_name), "Reverse query name for '%s' clashes with field name '%s'." % (field_name, clash_name), hint=("Rename field '%s', or add/change a related_name " "argument to the definition for field '%s'.") % (clash_name, field_name), obj=self, id='E015', id='fields.E303', ) ) Loading @@ -223,22 +221,22 @@ class RelatedField(Field): if clash_field.get_accessor_name() == rel_name: errors.append( checks.Error( 'Clash between accessors for %s and %s.' % (field_name, clash_name), hint=('Add or change a related_name argument ' 'to the definition for %s or %s.') % (field_name, clash_name), "Reverse accessor for '%s' clashes with reverse accessor for '%s'." % (field_name, clash_name), hint=("Add or change a related_name argument " "to the definition for '%s' or '%s'.") % (field_name, clash_name), obj=self, id='E016', id='fields.E304', ) ) if clash_field.get_accessor_name() == rel_query_name: errors.append( checks.Error( 'Clash between reverse query names for %s and %s.' % (field_name, clash_name), hint=('Add or change a related_name argument ' 'to the definition for %s or %s.') % (field_name, clash_name), "Reverse query name for '%s' clashes with reverse query name for '%s'." % (field_name, clash_name), hint=("Add or change a related_name argument " "to the definition for '%s' or '%s'.") % (field_name, clash_name), obj=self, id='E017', id='fields.E305', ) ) Loading Loading @@ -1317,17 +1315,15 @@ class ForeignObject(RelatedField): has_unique_field = any(rel_field.unique for rel_field in self.foreign_related_fields) if not has_unique_field and len(self.foreign_related_fields) > 1: field_combination = ','.join(rel_field.name field_combination = ', '.join("'%s'" % rel_field.name for rel_field in self.foreign_related_fields) model_name = self.rel.to.__name__ return [ checks.Error( ('No unique=True constraint ' 'on field combination "%s" under model %s.') % (field_combination, model_name), hint=('Set unique=True argument on any of the fields ' '"%s" under model %s.') % (field_combination, model_name), "None of the fields %s on model '%s' have a unique=True constraint." % (field_combination, model_name), hint=None, obj=self, id='E018', id='fields.E310', ) ] elif not has_unique_field: Loading @@ -1335,11 +1331,11 @@ class ForeignObject(RelatedField): model_name = self.rel.to.__name__ return [ checks.Error( ('%s.%s must have unique=True ' 'because it is referenced by a foreign key.') % (model_name, field_name), ("'%s.%s' must set unique=True " "because it is referenced by a foreign key.") % (model_name, field_name), hint=None, obj=self, id='E019', id='fields.E311', ) ] else: Loading Loading @@ -1605,19 +1601,19 @@ class ForeignKey(ForeignObject): if on_delete == SET_NULL and not self.null: return [ checks.Error( 'The field specifies on_delete=SET_NULL, but cannot be null.', hint='Set null=True argument on the field.', 'Field specifies on_delete=SET_NULL, but cannot be null.', hint='Set null=True argument on the field, or change the on_delete rule.', obj=self, id='E020', id='fields.E320', ) ] elif on_delete == SET_DEFAULT and not self.has_default(): return [ checks.Error( 'The field specifies on_delete=SET_DEFAULT, but has no default value.', hint=None, 'Field specifies on_delete=SET_DEFAULT, but has no default value.', hint='Set a default value, or change the on_delete rule.', obj=self, id='E021', id='fields.E321', ) ] else: Loading Loading @@ -1864,10 +1860,10 @@ class ManyToManyField(RelatedField): if self.unique: return [ checks.Error( 'ManyToManyFields must not be unique.', 'ManyToManyFields cannot be unique.', hint=None, obj=self, id='E022', id='fields.E330', ) ] return [] Loading @@ -1879,13 +1875,11 @@ class ManyToManyField(RelatedField): # The relationship model is not installed. errors.append( checks.Error( ('The field specifies a many-to-many relation through model ' '%s, which has not been installed.') % self.rel.through, hint=('Ensure that you did not misspell the model name and ' 'the model is not abstract. Does your INSTALLED_APPS ' 'setting contain the app where %s is defined?') % self.rel.through, ("Field specifies a many-to-many relation through model " "'%s', which has not been installed.") % self.rel.through, hint=None, obj=self, id='E023', id='fields.E331', ) ) Loading Loading @@ -1914,7 +1908,7 @@ class ManyToManyField(RelatedField): 'Many-to-many fields with intermediate tables must not be symmetrical.', hint=None, obj=self, id='E024', id='fields.E332', ) ) Loading @@ -1926,12 +1920,12 @@ class ManyToManyField(RelatedField): if seen_self > 2: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than two foreign keys ' 'to %s, which is ambiguous and is not permitted.') % (self, from_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than two foreign keys " "to '%s', which is ambiguous.") % (self, from_model_name), hint=None, obj=self.rel.through, id='E025', id='fields.E333', ) ) Loading @@ -1945,41 +1939,41 @@ class ManyToManyField(RelatedField): if seen_from > 1: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than one foreign key ' 'to %s, which is ambiguous and is not permitted.') % (self, from_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than one foreign key " "from '%s', which is ambiguous.") % (self, from_model_name), hint=('If you want to create a recursive relationship, ' 'use ForeignKey("self", symmetrical=False, ' 'through="%s").') % relationship_model_name, obj=self, id='E026', id='fields.E334', ) ) if seen_to > 1: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it has more than one foreign key ' 'to %s, which is ambiguous and is not permitted.') % (self, to_model_name), ("The model is used as an intermediate model by " "'%s', but it has more than one foreign key " "to '%s', which is ambiguous.") % (self, to_model_name), hint=('If you want to create a recursive ' 'relationship, use ForeignKey("self", ' 'symmetrical=False, through="%s").') % relationship_model_name, obj=self, id='E027', id='fields.E335', ) ) if seen_from == 0 or seen_to == 0: errors.append( checks.Error( ('The model is used as an intermediary model by ' '%s, but it misses a foreign key to %s or %s.') % ( ("The model is used as an intermediate model by " "'%s', but it does not have a foreign key to '%s' or '%s'.") % ( self, from_model_name, to_model_name ), hint=None, obj=self.rel.through, id='E028', id='fields.E336', ) ) return errors Loading
tests/contenttypes_tests/tests.py +11 −13 File changed.Preview size limit exceeded, changes collapsed. Show changes