Opened 4 years ago

Closed 4 years ago

#31286 closed Bug (fixed)

Database specific fields checks should be databases aware.

Reported by: Hongtao Ma Owned by: Hongtao Ma
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Simon Charette Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

In an attempt to trigger the check Error mentioned in Tickets: #31144, I found that the check for database backend doesn't check against the backend specified, e.g. --database mysql, rather, it always checks against the 'default' backend.

After diving into the source code, I found the following method defined in django/db/models/fields/init.py

    def _check_backend_specific_checks(self, **kwargs):
        app_label = self.model._meta.app_label
        for db in connections:
            if router.allow_migrate(db, app_label, model_name=self.model._meta.model_name):
                return connections[db].validation.check_field(self, **kwargs)
        return []

It checks the first db defined in connections rather those provided by users.

A proposed change would be:

    def _check_backend_specific_checks(self, **kwargs):
        app_label = self.model._meta.app_label
        errors = []
        for db in kwargs['databases'] or ['default']:
            if router.allow_migrate(db, app_label, model_name=self.model._meta.model_name):
                errors.extend(connections[db].validation.check_field(self, **kwargs))
        return errors

It worked as intended on my local machine.
I would happily provide a patch for this one.

Change History (6)

comment:1 by Mariusz Felisiak, 4 years ago

Cc: Simon Charette added
Easy pickings: set
Summary: Database specific checks always goes to the 'default' backendDatabase specific fields checks should be databases aware.
Triage Stage: UnreviewedAccepted

Thanks, this was missed in 0b83c8cc4db95812f1e15ca19d78614e94cf38dd. We should use here the same approach and pass databases to these checks:

diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 6bd95f542c..c54b8f6e31 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -335,11 +335,13 @@ class Field(RegisterLookupMixin):
         else:
             return []
 
-    def _check_backend_specific_checks(self, **kwargs):
+    def _check_backend_specific_checks(self, databases=None, **kwargs):
         app_label = self.model._meta.app_label
-        for db in connections:
-            if router.allow_migrate(db, app_label, model_name=self.model._meta.model_name):
-                return connections[db].validation.check_field(self, **kwargs)
+        if databases is None:
+            return []
+        for alias in databases:
+            if router.allow_migrate(alias, app_label, model_name=self.model._meta.model_name):
+                return connections[alias].validation.check_field(self, **kwargs)
         return []
 
     def _check_validators(self):

in reply to:  1 comment:2 by Hongtao Ma, 4 years ago

Owner: changed from nobody to Hongtao Ma
Status: newassigned

Applied the patch, two testcases failed, however:

  • FAIL: test_checks_called_on_the_default_database (check_framework.test_multi_db.TestMultiDBChecks)
  • FAIL: test_checks_called_on_the_other_database (check_framework.test_multi_db.TestMultiDBChecks)
        for alias in databases:
            if router.allow_migrate(alias, app_label, model_name=self.model._meta.model_name):
                return connections[alias].validation.check_field(self, **kwargs)
        return []

The early return will cause only a single backend be checked, in case of multiple backends provided:

(djangodev) ➜  my_test_proj git:(iss_check) ✗ python manage.py check --database sqlite3 --database mysql
System check identified no issues (0 silenced).
(djangodev) ➜  my_test_proj git:(iss_check) ✗ python manage.py check --database mysql        
SystemCheckError: System check identified some issues:

ERRORS:
issue.AnotherIndex.name: (mysql.E001) MySQL does not allow unique CharFields to have a max_length > 255.
issue.Networkservergroup.groupname: (mysql.E001) MySQL does not allow unique CharFields to have a max_length > 255.

System check identified 2 issues (0 silenced).
(djangodev) ➜  my_test_proj git:(iss_check) ✗ 

comment:3 by Mariusz Felisiak, 4 years ago

You have to pass databases={'default', 'other'} to model.check() calls in TestMultiDBChecks.

comment:4 by Hongtao Ma, 4 years ago

Has patch: set
Needs tests: set

comment:5 by Simon Charette, 4 years ago

Triage Stage: AcceptedReady for checkin

Thanks for the patch @Taoup!

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 4 years ago

Resolution: fixed
Status: assignedclosed

In 271fdab:

Fixed #31286 -- Made database specific fields checks databases aware.

Follow up to 0b83c8cc4db95812f1e15ca19d78614e94cf38dd.

Note: See TracTickets for help on using tickets.
Back to Top