#24346: AuthRouter docs lead to AttributeError: 'NoneType' object has no 
attribute
'_meta' with 0002_remove_content_type_name
-------------------------------+-----------------------
     Reporter:  pzrq           |      Owner:  nobody
         Type:  Bug            |     Status:  new
    Component:  Documentation  |    Version:  1.8alpha1
     Severity:  Normal         |   Keywords:
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+-----------------------
 #22583 passes `model=None` into `allow_migrate(db, model, **hints)`:
 
https://github.com/django/django/blob/8f4877c89d0f28e289399fbb46357623a49e7eb0/django/db/migrations/operations/special.py#L174

 #24099 introduced a `0002_remove_content_type_name` migration which uses
 this code path:
 
https://github.com/django/django/blob/b4ac23290772e0c11379eb2dfb81c750b7052b66/django/contrib/contenttypes/migrations/0002_remove_content_type_name.py

 When combined with the documented `AuthRouter` example:
 https://docs.djangoproject.com/en/1.8/topics/db/multi-db/#an-example

 This causes a stacktrace like the following in downstream projects:

 {{{
 $ ./manage.py test --verbosity=2
 Creating test database for alias 'default' (':memory:')...
 ...
 Running migrations:
   Rendering model states... DONE
   ...
   Applying contenttypes.0002_remove_content_type_name...Traceback (most
 recent call last):
   File "./manage.py", line 20, in <module>
     execute_from_command_line(sys.argv)
   File "/Users/pzrq/Projects/django/django/core/management/__init__.py",
 line 338, in execute_from_command_line
     utility.execute()
   File "/Users/pzrq/Projects/django/django/core/management/__init__.py",
 line 330, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File
 "/Users/pzrq/Projects/django/django/core/management/commands/test.py",
 line 30, in run_from_argv
     super(Command, self).run_from_argv(argv)
   File "/Users/pzrq/Projects/django/django/core/management/base.py", line
 390, in run_from_argv
     self.execute(*args, **cmd_options)
   File
 "/Users/pzrq/Projects/django/django/core/management/commands/test.py",
 line 74, in execute
     super(Command, self).execute(*args, **options)
   File "/Users/pzrq/Projects/django/django/core/management/base.py", line
 441, in execute
     output = self.handle(*args, **options)
   File
 "/Users/pzrq/Projects/django/django/core/management/commands/test.py",
 line 90, in handle
     failures = test_runner.run_tests(test_labels)
   File "/Users/pzrq/Projects/django/django/test/runner.py", line 210, in
 run_tests
     old_config = self.setup_databases()
   File "/Users/pzrq/Projects/django/django/test/runner.py", line 166, in
 setup_databases
     **kwargs
   File "/Users/pzrq/Projects/django/django/test/runner.py", line 370, in
 setup_databases
     serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE",
 True),
   File "/Users/pzrq/Projects/django/django/db/backends/base/creation.py",
 line 369, in create_test_db
     test_flush=True,
   File "/Users/pzrq/Projects/django/django/core/management/__init__.py",
 line 120, in call_command
     return command.execute(*args, **defaults)
   File "/Users/pzrq/Projects/django/django/core/management/base.py", line
 441, in execute
     output = self.handle(*args, **options)
   File
 "/Users/pzrq/Projects/django/django/core/management/commands/migrate.py",
 line 213, in handle
     executor.migrate(targets, plan, fake=options.get("fake", False))
   File "/Users/pzrq/Projects/django/django/db/migrations/executor.py",
 line 93, in migrate
     self.apply_migration(states[migration], migration, fake=fake)
   File "/Users/pzrq/Projects/django/django/db/migrations/executor.py",
 line 129, in apply_migration
     state = migration.apply(state, schema_editor)
   File "/Users/pzrq/Projects/django/django/db/migrations/migration.py",
 line 110, in apply
     operation.database_forwards(self.app_label, schema_editor, old_state,
 project_state)
   File
 "/Users/pzrq/Projects/django/django/db/migrations/operations/special.py",
 line 174, in database_forwards
     if self.allowed_to_migrate(schema_editor.connection.alias, None,
 hints=self.hints):
   File
 "/Users/pzrq/Projects/django/django/db/migrations/operations/base.py",
 line 109, in allowed_to_migrate
     return router.allow_migrate(connection_alias, model, **(hints or {}))
   File "/Users/pzrq/Projects/django/django/db/utils.py", line 334, in
 allow_migrate
     allow = method(db, model, **hints)
   File
 "/Users/pzrq/Projects/mathspace/msproblem/core/database_routers.py", line
 67, in allow_migrate
     elif model._meta.app_label in APP_LABELS:
 AttributeError: 'NoneType' object has no attribute '_meta'
 }}}

 This is documented here:
 https://docs.djangoproject.com/en/1.8/releases/1.8/#miscellaneous

 > The migration operations RunPython and RunSQL now call the
 allow_migrate() method of database routers. In these cases the model
 argument of allow_migrate() is set to None, so the router must properly
 handle this value.

 So I guess the fix is to update the docs to be consistent with the
 previously committed changes, e.g.

 {{{
 class AuthRouter(object):
     ...
     def allow_migrate(self, db, model=None, **hints):
         """
         Make sure the auth app only appears in the 'auth_db'
         database.
         """
         if model is None:
             # Handle RunPython or RunSQL
             return db == 'auth_db'

         if db == 'auth_db':
             return model._meta.app_label == 'auth'
         elif model._meta.app_label == 'auth':
             return False
         return None
 }}}

 Will add a Github PR for that shortly.

--
Ticket URL: <https://code.djangoproject.com/ticket/24346>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/047.c5db0e893adf68cf88e3c1c65e520f48%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to