Browse Source

Fixed #26401 -- Added BaseAuthConfig to use auth without migrations.

Jon Dufresne 8 years ago
parent
commit
1ec1633cb2

+ 14 - 2
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)

+ 17 - 0
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
+    <using-auth-without-models>` any of the built-in ``contrib.auth`` models.

+ 4 - 0
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 <using-auth-without-models>`.
+
 :mod:`django.contrib.contenttypes`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 25 - 0
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 <auth-custom-user>` 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',
+        ...
+    ]

+ 61 - 0
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)