def test_tenant_app_missing_from_install_apps(self): self.assertBestPractice([ Error("You have TENANT_APPS that are not in INSTALLED_APPS", hint=['django.contrib.flatpages']), ])
def test_printing_manager_error(self): manager = SimpleModel.manager e = Error("Error", hint=None, obj=manager) expected = "check_framework.SimpleModel.manager: Error" self.assertEqual(force_text(e), expected)
def test_tenant_apps_empty(self): self.assertBestPractice([ Error("TENANT_APPS is empty.", hint="Maybe you don't need this app?"), ])
def test_printing_field_error(self): field = SimpleModel._meta.get_field('field') e = Error("Error", hint=None, obj=field) expected = "check_framework.SimpleModel.field: Error" self.assertEqual(force_text(e), expected)
def test_printing_model_error(self): e = Error("Error", hint=None, obj=SimpleModel) expected = "check_framework.SimpleModel: Error" self.assertEqual(force_text(e), expected)
def test_printing_no_object(self): e = Error("Message", hint="Hint", obj=None) expected = "?: Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected)
def test_printing_with_given_id(self): e = Error("Message", hint="Hint", obj=DummyObj(), id="ID") expected = "obj: (ID) Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected)
def test_printing(self): e = Error("Message", hint="Hint", obj=DummyObj()) expected = "obj: Message\n\tHINT: Hint" self.assertEqual(force_text(e), expected)
def test_printing_no_hint(self): e = Error("Message", hint=None, obj=DummyObj()) expected = "obj: Message" self.assertEqual(force_text(e), expected)
def custom_error_system_check(app_configs, **kwargs): return [Error( 'Error', hint=None, id='myerrorcheck.E001', )]
import os from django.core.checks import Error, register E001 = Error( "You do not seem to have reprepro installed", id='aasemble.mirrorsvc.E001', ) @register(deploy=True) def reprepro_available(app_configs, **kwargs): for d in os.environ['PATH'].split(':'): if os.access(os.path.join(d, 'apt-mirror'), os.X_OK): return [] return [E001]
def test_lazy_reference_checks(self, apps): class DummyModel(models.Model): author = models.ForeignKey('Author', models.CASCADE) class Meta: app_label = 'invalid_models_tests' class DummyClass: def __call__(self, **kwargs): pass def dummy_method(self): pass def dummy_function(*args, **kwargs): pass apps.lazy_model_operation(dummy_function, ('auth', 'imaginarymodel')) apps.lazy_model_operation(dummy_function, ('fanciful_app', 'imaginarymodel')) post_init.connect(dummy_function, sender='missing-app.Model', apps=apps) post_init.connect(DummyClass(), sender='missing-app.Model', apps=apps) post_init.connect(DummyClass().dummy_method, sender='missing-app.Model', apps=apps) self.assertEqual(_check_lazy_references(apps), [ Error( "%r contains a lazy reference to auth.imaginarymodel, " "but app 'auth' doesn't provide model 'imaginarymodel'." % dummy_function, obj=dummy_function, id='models.E022', ), Error( "%r contains a lazy reference to fanciful_app.imaginarymodel, " "but app 'fanciful_app' isn't installed." % dummy_function, obj=dummy_function, id='models.E022', ), Error( "An instance of class 'DummyClass' was connected to " "the 'post_init' signal with a lazy reference to the sender " "'missing-app.model', but app 'missing-app' isn't installed.", hint=None, obj='invalid_models_tests.test_models', id='signals.E001', ), Error( "Bound method 'DummyClass.dummy_method' was connected to the " "'post_init' signal with a lazy reference to the sender " "'missing-app.model', but app 'missing-app' isn't installed.", hint=None, obj='invalid_models_tests.test_models', id='signals.E001', ), Error( "The field invalid_models_tests.DummyModel.author was declared " "with a lazy reference to 'invalid_models_tests.author', but app " "'invalid_models_tests' isn't installed.", hint=None, obj=DummyModel.author.field, id='fields.E307', ), Error( "The function 'dummy_function' was connected to the 'post_init' " "signal with a lazy reference to the sender " "'missing-app.model', but app 'missing-app' isn't installed.", hint=None, obj='invalid_models_tests.test_models', id='signals.E001', ), ])
def test_M2M_long_column_name(self): """ #13711 -- Model check for long M2M column names when database has column name length limits. """ allowed_len, db_alias = get_max_column_name_length() # A model with very long name which will be used to set relations to. class VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz(models.Model): title = models.CharField(max_length=11) # Main model for which checks will be performed. class ModelWithLongField(models.Model): m2m_field = models.ManyToManyField( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, related_name='rn1', ) m2m_field2 = models.ManyToManyField( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, related_name='rn2', through='m2msimple', ) m2m_field3 = models.ManyToManyField( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, related_name='rn3', through='m2mcomplex', ) fk = models.ForeignKey( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, models.CASCADE, related_name='rn4', ) # Models used for setting `through` in M2M field. class m2msimple(models.Model): id2 = models.ForeignKey(ModelWithLongField, models.CASCADE) class m2mcomplex(models.Model): id2 = models.ForeignKey(ModelWithLongField, models.CASCADE) long_field_name = 'a' * (self.max_column_name_length + 1) models.ForeignKey( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, models.CASCADE, ).contribute_to_class(m2msimple, long_field_name) models.ForeignKey( VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, models.CASCADE, db_column=long_field_name ).contribute_to_class(m2mcomplex, long_field_name) errors = ModelWithLongField.check() # First error because of M2M field set on the model with long name. m2m_long_name = "verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz_id" if self.max_column_name_length > len(m2m_long_name): # Some databases support names longer than the test name. expected = [] else: expected = [ Error( 'Autogenerated column name too long for M2M field "%s". ' 'Maximum length is "%s" for database "%s".' % (m2m_long_name, self.max_column_name_length, self.column_limit_db_alias), hint="Use 'through' to create a separate model for " "M2M and then set column_name using 'db_column'.", obj=ModelWithLongField, id='models.E019', ) ] # Second error because the FK specified in the `through` model # `m2msimple` has auto-generated name longer than allowed. # There will be no check errors in the other M2M because it # specifies db_column for the FK in `through` model even if the actual # name is longer than the limits of the database. expected.append( Error( 'Autogenerated column name too long for M2M field "%s_id". ' 'Maximum length is "%s" for database "%s".' % (long_field_name, self.max_column_name_length, self.column_limit_db_alias), hint="Use 'through' to create a separate model for " "M2M and then set column_name using 'db_column'.", obj=ModelWithLongField, id='models.E019', ) ) self.assertEqual(errors, expected)
def check_all_models(app_configs=None, **kwargs): db_table_models = defaultdict(list) indexes = defaultdict(list) constraints = defaultdict(list) errors = [] if app_configs is None: models = apps.get_models() else: models = chain.from_iterable(app_config.get_models() for app_config in app_configs) for model in models: if model._meta.managed and not model._meta.proxy: db_table_models[model._meta.db_table].append(model._meta.label) if not inspect.ismethod(model.check): errors.append( Error( "The '%s.check()' class method is currently overridden by %r." % (model.__name__, model.check), obj=model, id='models.E020' ) ) else: errors.extend(model.check(**kwargs)) for model_index in model._meta.indexes: indexes[model_index.name].append(model._meta.label) for model_constraint in model._meta.constraints: constraints[model_constraint.name].append(model._meta.label) if settings.DATABASE_ROUTERS: error_class, error_id = Warning, 'models.W035' error_hint = ( 'You have configured settings.DATABASE_ROUTERS. Verify that %s ' 'are correctly routed to separate databases.' ) else: error_class, error_id = Error, 'models.E028' error_hint = None for db_table, model_labels in db_table_models.items(): if len(model_labels) != 1: model_labels_str = ', '.join(model_labels) errors.append( error_class( "db_table '%s' is used by multiple models: %s." % (db_table, model_labels_str), obj=db_table, hint=(error_hint % model_labels_str) if error_hint else None, id=error_id, ) ) for index_name, model_labels in indexes.items(): if len(model_labels) > 1: model_labels = set(model_labels) errors.append( Error( "index name '%s' is not unique %s %s." % ( index_name, 'for model' if len(model_labels) == 1 else 'amongst models:', ', '.join(sorted(model_labels)), ), id='models.E029' if len(model_labels) == 1 else 'models.E030', ), ) for constraint_name, model_labels in constraints.items(): if len(model_labels) > 1: model_labels = set(model_labels) errors.append( Error( "constraint name '%s' is not unique %s %s." % ( constraint_name, 'for model' if len(model_labels) == 1 else 'amongst models:', ', '.join(sorted(model_labels)), ), id='models.E031' if len(model_labels) == 1 else 'models.E032', ), ) return errors