def validate_field(self, errors, opts, f): """ There are some field length restrictions for MySQL: - Prior to version 5.0.3, character fields could not exceed 255 characters in length. - No character (varchar) fields can have a length exceeding 255 characters if they have a unique index on them. """ from django.db import models from django.db import connection db_version = connection.get_server_version() varchar_fields = (models.CharField, models.CommaSeparatedIntegerField, models.SlugField) if isinstance(f, varchar_fields) and f.max_length > 255: if db_version < (5, 0, 3): msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %(version)s).' elif f.unique == True: msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".' else: msg = None if msg: errors.add( opts, msg % { 'name': f.name, 'cls': f.__class__.__name__, 'version': '.'.join([str(n) for n in db_version[:3]]) })
def _get_engine_version(self): """ Access method for engine_version property. engine_version return a full version in string format (ie: 'WI-V6.3.5.4926 Firebird 1.5' ) """ if self._engine_version is None: from django.db import connection self._engine_version = connection.get_server_version() return self._engine_version
def validate_field(self, errors, opts, f): "Prior to MySQL 5.0.3, character fields could not exceed 255 characters" from django.db import models from django.db import connection db_version = connection.get_server_version() if db_version < (5, 0, 3) and isinstance( f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: errors.add( opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join( [str(n) for n in db_version[:3]])))
def validate_field(self, errors, opts, f): "Prior to MySQL 5.0.3, character fields could not exceed 255 characters" from django.db import models from django.db import connection db_version = connection.get_server_version() if ( db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255 ): errors.add( opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, ".".join([str(n) for n in db_version[:3]])), )
def test_dates_with_aggregation(self): """ .dates() returns a distinct set of dates when applied to a QuerySet with aggregation. Refs #18056. Previously, .dates() would return distinct (date_kind, aggregation) sets, in this case (year, num_authors), so 2008 would be returned twice because there are books from 2008 with a different number of authors. """ srv_ver = connection.get_server_version() if (12, 0, 0, 0) <= srv_ver < (13, 0, 0, 0): # this test fails on SQL server 2014 self.skipTest( "TODO fix django.db.utils.OperationalError: ORDER BY items must appear in the select list if SELECT DISTINCT is specified." ) dates = Book.objects.annotate(num_authors=Count("authors")).dates( 'pubdate', 'year') self.assertQuerysetEqual(dates, [ "datetime.date(1991, 1, 1)", "datetime.date(1995, 1, 1)", "datetime.date(2007, 1, 1)", "datetime.date(2008, 1, 1)" ])
def test_dates_with_aggregation(self): """ .dates() returns a distinct set of dates when applied to a QuerySet with aggregation. Refs #18056. Previously, .dates() would return distinct (date_kind, aggregation) sets, in this case (year, num_authors), so 2008 would be returned twice because there are books from 2008 with a different number of authors. """ srv_ver = connection.get_server_version() if (12, 0, 0, 0) <= srv_ver < (13, 0, 0, 0): # this test fails on SQL server 2014 self.skipTest("TODO fix django.db.utils.OperationalError: ORDER BY items must appear in the select list if SELECT DISTINCT is specified.") dates = Book.objects.annotate(num_authors=Count("authors")).dates('pubdate', 'year') self.assertQuerysetEqual( dates, [ "datetime.date(1991, 1, 1)", "datetime.date(1995, 1, 1)", "datetime.date(2007, 1, 1)", "datetime.date(2008, 1, 1)" ] )
def validate_field(self, errors, opts, f): """ There are some field length restrictions for MySQL: - Prior to version 5.0.3, character fields could not exceed 255 characters in length. - No character (varchar) fields can have a length exceeding 255 characters if they have a unique index on them. """ from django.db import models from django.db import connection db_version = connection.get_server_version() varchar_fields = (models.CharField, models.CommaSeparatedIntegerField, models.SlugField) if isinstance(f, varchar_fields) and f.max_length > 255: if db_version < (5, 0, 3): msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %(version)s).' elif f.unique == True: msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".' else: msg = None if msg: errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__, 'version': '.'.join([str(n) for n in db_version[:3]])})
def get_validation_errors(outfile, app=None): """ Validates all models that are part of the specified app. If no app name is provided, validates all models of all installed apps. Writes errors, if any, to outfile. Returns number of errors. """ from django.conf import settings from django.db import models, connection from django.db.models.loading import get_app_errors from django.db.models.fields.related import RelatedObject e = ModelErrorCollection(outfile) for (app_name, error) in get_app_errors().items(): e.add(app_name, error) for cls in models.get_models(app): opts = cls._meta # Do field-specific validation. for f in opts.local_fields: if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': 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) if f.name.endswith('_'): e.add(opts, '"%s": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.' % f.name) if isinstance(f, models.CharField) and f.max_length in (None, 0): e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name) if isinstance(f, models.DecimalField): if f.decimal_places is None: e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name) if f.max_digits is None: e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name) if isinstance(f, models.FileField) and not f.upload_to: e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name) if isinstance(f, models.ImageField): try: from PIL import Image except ImportError: 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) if f.choices: if isinstance(f.choices, basestring) or not is_iterable(f.choices): e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name) else: for c in f.choices: if not type(c) in (tuple, list) or len(c) != 2: e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name) if f.db_index not in (None, True, False): e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name) # Check that max_length <= 255 if using older MySQL versions. if settings.DATABASE_ENGINE == 'mysql': db_version = connection.get_server_version() if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) # Check to see if the related field will clash with any existing # fields, m2m fields, m2m related objects or related objects if f.rel: if f.rel.to not in models.get_models(): e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section if isinstance(f.rel.to, (str, unicode)): continue rel_opts = f.rel.to._meta rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() for r in rel_opts.fields: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.local_many_to_many: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.get_all_related_many_to_many_objects(): if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for r in rel_opts.get_all_related_objects(): if r.field is not f: if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for i, f in enumerate(opts.local_many_to_many): # Check to see if the related m2m field will clash with any # existing fields, m2m fields, m2m related objects or related # objects if f.rel.to not in models.get_models(): e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section if isinstance(f.rel.to, (str, unicode)): continue rel_opts = f.rel.to._meta rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() # If rel_name is none, there is no reverse accessor (this only # occurs for symmetrical m2m relations to self). If this is the # case, there are no clashes to check for this field, as there are # no reverse descriptors for this field. if rel_name is not None: for r in rel_opts.fields: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.local_many_to_many: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.get_all_related_many_to_many_objects(): if r.field is not f: if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for r in rel_opts.get_all_related_objects(): if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) # Check ordering attribute. if opts.ordering: for field_name in opts.ordering: if field_name == '?': continue if field_name.startswith('-'): field_name = field_name[1:] if opts.order_with_respect_to and field_name == '_order': continue # Skip ordering in the format field1__field2 (FIXME: checking # this format would be nice, but it's a little fiddly). if '_' in field_name: continue try: opts.get_field(field_name, many_to_many=False) except models.FieldDoesNotExist: e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) # Check unique_together. for ut in opts.unique_together: for field_name in ut: try: f = opts.get_field(field_name, many_to_many=True) except models.FieldDoesNotExist: e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name) else: if isinstance(f.rel, models.ManyToManyRel): e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name) if f not in opts.local_fields: e.add(opts, '"unique_together" refers to %s. This is not in the same model as the unique_together statement.' % f.name) return len(e.errors)
def get_validation_errors(outfile, app=None): """ Validates all models that are part of the specified app. If no app name is provided, validates all models of all installed apps. Writes errors, if any, to outfile. Returns number of errors. """ from django.conf import settings from django.db import models, connection from django.db.models.loading import get_app_errors from django.db.models.fields.related import RelatedObject e = ModelErrorCollection(outfile) for (app_name, error) in get_app_errors().items(): e.add(app_name, error) for cls in models.get_models(app): opts = cls._meta # Do field-specific validation. for f in opts.fields: if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': 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) if f.name.endswith('_'): e.add( opts, '"%s": Field names cannot end with underscores, because this would lead to ambiguous queryset filters.' % f.name) if isinstance(f, models.CharField) and f.max_length in (None, 0): e.add( opts, '"%s": CharFields require a "max_length" attribute.' % f.name) if isinstance(f, models.DecimalField): if f.decimal_places is None: e.add( opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name) if f.max_digits is None: e.add( opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name) if isinstance(f, models.FileField) and not f.upload_to: e.add( opts, '"%s": FileFields require an "upload_to" attribute.' % f.name) if isinstance(f, models.ImageField): try: from PIL import Image except ImportError: 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) if f.prepopulate_from is not None and type( f.prepopulate_from) not in (list, tuple): e.add( opts, '"%s": prepopulate_from should be a list or tuple.' % f.name) if f.choices: if isinstance(f.choices, basestring) or not is_iterable(f.choices): e.add( opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name) else: for c in f.choices: if not type(c) in (tuple, list) or len(c) != 2: e.add( opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name) if f.db_index not in (None, True, False): e.add( opts, '"%s": "db_index" should be either None, True or False.' % f.name) # Check that max_length <= 255 if using older MySQL versions. if settings.DATABASE_ENGINE == 'mysql': db_version = connection.get_server_version() if db_version < (5, 0, 3) and isinstance( f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: e.add( opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join( [str(n) for n in db_version[:3]]))) # Check to see if the related field will clash with any # existing fields, m2m fields, m2m related objects or related objects if f.rel: if f.rel.to not in models.get_models(): e.add( opts, "'%s' has relation with model %s, which has not been installed" % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section if isinstance(f.rel.to, (str, unicode)): continue rel_opts = f.rel.to._meta rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() for r in rel_opts.fields: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.many_to_many: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.get_all_related_many_to_many_objects(): if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for r in rel_opts.get_all_related_objects(): if r.field is not f: if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for i, f in enumerate(opts.many_to_many): # Check to see if the related m2m field will clash with any # existing fields, m2m fields, m2m related objects or related objects if f.rel.to not in models.get_models(): e.add( opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, f.rel.to)) # it is a string and we could not find the model it refers to # so skip the next section if isinstance(f.rel.to, (str, unicode)): continue rel_opts = f.rel.to._meta rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() rel_query_name = f.related_query_name() # If rel_name is none, there is no reverse accessor. # (This only occurs for symmetrical m2m relations to self). # If this is the case, there are no clashes to check for this field, as # there are no reverse descriptors for this field. if rel_name is not None: for r in rel_opts.fields: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.many_to_many: if r.name == rel_name: 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)) if r.name == rel_query_name: 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)) for r in rel_opts.get_all_related_many_to_many_objects(): if r.field is not f: if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) for r in rel_opts.get_all_related_objects(): if r.get_accessor_name() == rel_name: 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)) if r.get_accessor_name() == rel_query_name: 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)) # Check admin attribute. if opts.admin is not None: if not isinstance(opts.admin, models.AdminOptions): e.add( opts, '"admin" attribute, if given, must be set to a models.AdminOptions() instance.' ) else: # list_display if not isinstance(opts.admin.list_display, (list, tuple)): e.add( opts, '"admin.list_display", if given, must be set to a list or tuple.' ) else: for fn in opts.admin.list_display: try: f = opts.get_field(fn) except models.FieldDoesNotExist: if not hasattr(cls, fn): e.add( opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn) else: if isinstance(f, models.ManyToManyField): e.add( opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn) # list_display_links if opts.admin.list_display_links and not opts.admin.list_display: e.add( opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.' ) if not isinstance(opts.admin.list_display_links, (list, tuple)): e.add( opts, '"admin.list_display_links", if given, must be set to a list or tuple.' ) else: for fn in opts.admin.list_display_links: try: f = opts.get_field(fn) except models.FieldDoesNotExist: if not hasattr(cls, fn): e.add( opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn) if fn not in opts.admin.list_display: e.add( opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn) # list_filter if not isinstance(opts.admin.list_filter, (list, tuple)): e.add( opts, '"admin.list_filter", if given, must be set to a list or tuple.' ) else: for fn in opts.admin.list_filter: try: f = opts.get_field(fn) except models.FieldDoesNotExist: e.add( opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) # date_hierarchy if opts.admin.date_hierarchy: try: f = opts.get_field(opts.admin.date_hierarchy) except models.FieldDoesNotExist: e.add( opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy) # Check ordering attribute. if opts.ordering: for field_name in opts.ordering: if field_name == '?': continue if field_name.startswith('-'): field_name = field_name[1:] if opts.order_with_respect_to and field_name == '_order': continue if '.' in field_name: continue # Skip ordering in the format 'table.field'. try: opts.get_field(field_name, many_to_many=False) except models.FieldDoesNotExist: e.add( opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) # Check core=True, if needed. for related in opts.get_followed_related_objects(): if not related.edit_inline: continue try: for f in related.opts.fields: if f.core: raise StopIteration e.add( related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name)) except StopIteration: pass # Check unique_together. for ut in opts.unique_together: for field_name in ut: try: f = opts.get_field(field_name, many_to_many=True) except models.FieldDoesNotExist: e.add( opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name) else: if isinstance(f.rel, models.ManyToManyRel): e.add( opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name) return len(e.errors)
def test_server_version_connections(self): connection.close() connection.get_server_version() self.assertTrue(connection.connection is None)