From 1ec1633cb294d8ce2a65ece6b56c258483596fba Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sat, 10 Sep 2016 16:38:05 -0700 Subject: [PATCH] Fixed #26401 -- Added BaseAuthConfig to use auth without migrations. --- django/contrib/auth/apps.py | 16 +++++++-- docs/ref/contrib/auth.txt | 17 +++++++++ docs/releases/1.11.txt | 4 +++ docs/topics/auth/customizing.txt | 25 +++++++++++++ tests/auth_tests/test_apps.py | 61 ++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 tests/auth_tests/test_apps.py diff --git a/django/contrib/auth/apps.py b/django/contrib/auth/apps.py index d5590158cf..9d128db39c 100644 --- a/django/contrib/auth/apps.py +++ b/django/contrib/auth/apps.py @@ -7,14 +7,26 @@ from .checks import check_models_permissions, check_user_model from .management import create_permissions -class AuthConfig(AppConfig): +class BaseAuthConfig(AppConfig): + """ + AppConfig which assumes that the auth models don't exist. + """ name = 'django.contrib.auth' verbose_name = _("Authentication and Authorization") def ready(self): + checks.register(check_user_model, checks.Tags.models) + + +class AuthConfig(BaseAuthConfig): + """ + The default AppConfig for auth. + """ + + def ready(self): + super(AuthConfig, self).ready() post_migrate.connect( create_permissions, dispatch_uid="django.contrib.auth.management.create_permissions" ) - checks.register(check_user_model, checks.Tags.models) checks.register(check_models_permissions, checks.Tags.models) diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt index 91e3fbd1ba..f12b16daa0 100644 --- a/docs/ref/contrib/auth.txt +++ b/docs/ref/contrib/auth.txt @@ -645,3 +645,20 @@ The following backends are available in :mod:`django.contrib.auth.backends`: Same as :class:`RemoteUserBackend` except that it doesn't reject inactive users because :attr:`~RemoteUserBackend.user_can_authenticate` always returns ``True``. + +``AppConfig`` classes +===================== + +.. module:: django.contrib.auth.apps + :synopsis: AppConfigs for contrib.auth. + +.. class:: AuthConfig + + The default :class:`~django.apps.AppConfig`. + +.. class:: BaseAuthConfig + + .. versionadded:: 1.11 + + An :class:`~django.apps.AppConfig` for use if you :ref:`aren't using + ` any of the built-in ``contrib.auth`` models. diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index 49540a320a..b2ba159c8a 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -109,6 +109,10 @@ Minor features * Added password validators ``help_text`` to :class:`~django.contrib.auth.forms.UserCreationForm`. +* The new :class:`~django.contrib.auth.apps.BaseAuthConfig` ``AppConfig`` + allows using the authentication system :ref:`without any of the built-in + models `. + :mod:`django.contrib.contenttypes` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index db18bfb8c2..d102d9939b 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -1133,3 +1133,28 @@ Finally, specify the custom model as the default user model for your project using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``:: AUTH_USER_MODEL = 'customauth.MyUser' + +.. _using-auth-without-models: + +Using ``contrib.auth`` without the built-in models +================================================== + +The models shipped with ``contrib.auth`` may not be required. For example, if +you :ref:`customize the user model ` and don't use the +:class:`~django.contrib.auth.models.Permission` and +:class:`~django.contrib.auth.models.Group` models, then the ``auth`` tables +may be unused. To avoid creating these tables, modify the +:setting:`MIGRATION_MODULES` setting and disable the migrations for the +``auth`` app:: + + MIGRATION_MODULES = {'auth': None} + +To prevent creation of the default permissions, change ``'django.contrib.auth'`` +in :setting:`INSTALLED_APPS` to +:class:`django.contrib.auth.apps.BaseAuthConfig`:: + + INSTALLED_APPS = [ + ... + 'django.contrib.auth.apps.BaseAuthConfig', + ... + ] diff --git a/tests/auth_tests/test_apps.py b/tests/auth_tests/test_apps.py new file mode 100644 index 0000000000..e1c386c95e --- /dev/null +++ b/tests/auth_tests/test_apps.py @@ -0,0 +1,61 @@ +import os +import shutil +import subprocess +import sys +import tempfile +import unittest + +from django.db import ConnectionHandler + +SETTINGS = """ +SECRET_KEY = 'django_auth_tests_secret_key' + +INSTALLED_APPS = [ + 'django.contrib.auth.apps.BaseAuthConfig', + 'django.contrib.contenttypes', +] + +MIGRATION_MODULES = {'auth': None} + +DATABASES = %(databases)r +""" + + +class AppConfigTests(unittest.TestCase): + def test_no_migrations(self): + project_path = tempfile.mkdtemp() + try: + databases = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(project_path, 'db.sqlite3'), + } + } + + with open(os.path.join(project_path, 'no_migrations.py'), 'w') as fp: + fp.write(SETTINGS % {'databases': databases}) + + with open(os.devnull, 'wb') as devnull: + cmd = [ + sys.executable, + '-m', 'django', + 'migrate', + '--settings', 'no_migrations', + '--pythonpath', project_path, + ] + returncode = subprocess.call(cmd, stdout=devnull, stderr=devnull) + + # Migrate command ran without errors. + self.assertEqual(returncode, 0) + + # Auth tables weren't created. + conns = ConnectionHandler(databases) + try: + self.assertEqual( + set(conns['default'].introspection.table_names()), + {'django_content_type', 'django_migrations'}, + ) + finally: + conns.close_all() + finally: + shutil.rmtree(project_path)