﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
24346	AuthRouter docs lead to AttributeError: 'NoneType' object has no attribute '_meta' with 0002_remove_content_type_name	Peter Schmidt	nobody	"#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."	Bug	closed	Documentation	1.8alpha1	Release blocker	fixed			Accepted	1	0	0	1	0	0
