diff --git a/django/contrib/admin/forms.py b/django/contrib/admin/forms.py
index e790e2e3b6..4e828697e8 100644
--- a/django/contrib/admin/forms.py
+++ b/django/contrib/admin/forms.py
@@ -9,6 +9,7 @@ from django.utils.translation import ugettext_lazy, ugettext as _
ERROR_MESSAGE = ugettext_lazy("Please enter the correct username and password "
"for a staff account. Note that both fields are case-sensitive.")
+
class AdminAuthenticationForm(AuthenticationForm):
"""
A custom authentication form used in the admin app.
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 4bb6440877..e57eafe256 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -2,7 +2,7 @@ from functools import update_wrapper
from django.http import Http404, HttpResponseRedirect
from django.contrib.admin import ModelAdmin, actions
from django.contrib.admin.forms import AdminAuthenticationForm
-from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.contrib.contenttypes import views as contenttype_views
from django.views.decorators.csrf import csrf_protect
from django.db.models.base import ModelBase
@@ -79,20 +79,23 @@ class AdminSite(object):
if model in self._registry:
raise AlreadyRegistered('The model %s is already registered' % model.__name__)
- # If we got **options then dynamically construct a subclass of
- # admin_class with those **options.
- if options:
- # For reasons I don't quite understand, without a __module__
- # the created class appears to "live" in the wrong place,
- # which causes issues later on.
- options['__module__'] = __name__
- admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
+ # Ignore the registration if the model has been
+ # swapped out.
+ if not model._meta.swapped:
+ # If we got **options then dynamically construct a subclass of
+ # admin_class with those **options.
+ if options:
+ # For reasons I don't quite understand, without a __module__
+ # the created class appears to "live" in the wrong place,
+ # which causes issues later on.
+ options['__module__'] = __name__
+ admin_class = type("%sAdmin" % model.__name__, (admin_class,), options)
- # Validate (which might be a no-op)
- validate(admin_class, model)
+ # Validate (which might be a no-op)
+ validate(admin_class, model)
- # Instantiate the admin class to save in the registry
- self._registry[model] = admin_class(model, self)
+ # Instantiate the admin class to save in the registry
+ self._registry[model] = admin_class(model, self)
def unregister(self, model_or_iterable):
"""
@@ -317,6 +320,7 @@ class AdminSite(object):
REDIRECT_FIELD_NAME: request.get_full_path(),
}
context.update(extra_context or {})
+
defaults = {
'extra_context': context,
'current_app': self.name,
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index caa26744d4..3d2a07eba2 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -26,7 +26,7 @@
{% if user.is_active and user.is_staff %}
{% trans 'Welcome,' %}
- {% filter force_escape %}{% firstof user.first_name user.username %}{% endfilter %}.
+ {% filter force_escape %}{% firstof user.get_short_name user.username %}{% endfilter %}.
{% block userlinks %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index 0b3ccf7d8c..d5d4430dc0 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -6,9 +6,10 @@ SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend'
REDIRECT_FIELD_NAME = 'next'
+
def load_backend(path):
i = path.rfind('.')
- module, attr = path[:i], path[i+1:]
+ module, attr = path[:i], path[i + 1:]
try:
mod = import_module(module)
except ImportError as e:
@@ -21,6 +22,7 @@ def load_backend(path):
raise ImproperlyConfigured('Module "%s" does not define a "%s" authentication backend' % (module, attr))
return cls()
+
def get_backends():
from django.conf import settings
backends = []
@@ -30,6 +32,7 @@ def get_backends():
raise ImproperlyConfigured('No authentication backends have been defined. Does AUTHENTICATION_BACKENDS contain anything?')
return backends
+
def authenticate(**credentials):
"""
If the given credentials are valid, return a User object.
@@ -46,6 +49,7 @@ def authenticate(**credentials):
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user
+
def login(request, user):
"""
Persist a user id and a backend in the request. This way a user doesn't
@@ -69,6 +73,7 @@ def login(request, user):
request.user = user
user_logged_in.send(sender=user.__class__, request=request, user=user)
+
def logout(request):
"""
Removes the authenticated user's ID from the request and flushes their
@@ -86,6 +91,16 @@ def logout(request):
from django.contrib.auth.models import AnonymousUser
request.user = AnonymousUser()
+
+def get_user_model():
+ "Return the User model that is active in this project"
+ from django.conf import settings
+ from django.db.models import get_model
+
+ app_label, model_name = settings.AUTH_USER_MODEL.split('.')
+ return get_model(app_label, model_name)
+
+
def get_user(request):
from django.contrib.auth.models import AnonymousUser
try:
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py
index 04fbef4788..da4c9c727a 100644
--- a/django/contrib/auth/backends.py
+++ b/django/contrib/auth/backends.py
@@ -1,4 +1,5 @@
-from django.contrib.auth.models import User, Permission
+from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Permission
class ModelBackend(object):
@@ -10,10 +11,13 @@ class ModelBackend(object):
# configurable.
def authenticate(self, username=None, password=None):
try:
- user = User.objects.get(username=username)
+ UserModel = get_user_model()
+ user = UserModel.objects.get(**{
+ getattr(UserModel, 'USERNAME_FIELD', 'username'): username
+ })
if user.check_password(password):
return user
- except User.DoesNotExist:
+ except UserModel.DoesNotExist:
return None
def get_group_permissions(self, user_obj, obj=None):
@@ -58,8 +62,9 @@ class ModelBackend(object):
def get_user(self, user_id):
try:
- return User.objects.get(pk=user_id)
- except User.DoesNotExist:
+ UserModel = get_user_model()
+ return UserModel.objects.get(pk=user_id)
+ except UserModel.DoesNotExist:
return None
@@ -92,17 +97,23 @@ class RemoteUserBackend(ModelBackend):
user = None
username = self.clean_username(remote_user)
+ UserModel = get_user_model()
+
# Note that this could be accomplished in one try-except clause, but
# instead we use get_or_create when creating unknown users since it has
# built-in safeguards for multiple threads.
if self.create_unknown_user:
- user, created = User.objects.get_or_create(username=username)
+ user, created = UserModel.objects.get_or_create(**{
+ getattr(UserModel, 'USERNAME_FIELD', 'username'): username
+ })
if created:
user = self.configure_user(user)
else:
try:
- user = User.objects.get(username=username)
- except User.DoesNotExist:
+ user = UserModel.objects.get(**{
+ getattr(UserModel, 'USERNAME_FIELD', 'username'): username
+ })
+ except UserModel.DoesNotExist:
pass
return user
diff --git a/django/contrib/auth/management/__init__.py b/django/contrib/auth/management/__init__.py
index 8287c97d58..2ae4084416 100644
--- a/django/contrib/auth/management/__init__.py
+++ b/django/contrib/auth/management/__init__.py
@@ -5,10 +5,9 @@ import getpass
import locale
import unicodedata
-from django.contrib.auth import models as auth_app
+from django.contrib.auth import models as auth_app, get_user_model
from django.core import exceptions
from django.db.models import get_models, signals
-from django.contrib.auth.models import User, get_user_model
def _get_permission_codename(action, opts):
@@ -106,7 +105,7 @@ def get_default_username(check_db=True):
"""
# If the User model has been swapped out, we can't make any assumptions
# about the default user name.
- if User._meta.swapped:
+ if auth_app.User._meta.swapped:
return ''
default_username = get_system_username()
@@ -118,15 +117,15 @@ def get_default_username(check_db=True):
# Run the username validator
try:
- User._meta.get_field('username').run_validators(default_username)
+ auth_app.User._meta.get_field('username').run_validators(default_username)
except exceptions.ValidationError:
return ''
# Don't return the default username if it is already taken.
if check_db and default_username:
try:
- User.objects.get(username=default_username)
- except User.DoesNotExist:
+ auth_app.User.objects.get(username=default_username)
+ except auth_app.User.DoesNotExist:
pass
else:
return ''
diff --git a/django/contrib/auth/management/commands/changepassword.py b/django/contrib/auth/management/commands/changepassword.py
index 2a8a19e6cb..1a2387442c 100644
--- a/django/contrib/auth/management/commands/changepassword.py
+++ b/django/contrib/auth/management/commands/changepassword.py
@@ -1,8 +1,8 @@
import getpass
from optparse import make_option
+from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError
-from django.contrib.auth.models import get_user_model
from django.db import DEFAULT_DB_ALIAS
diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py
index ffe248753a..3db1b877e1 100644
--- a/django/contrib/auth/management/commands/createsuperuser.py
+++ b/django/contrib/auth/management/commands/createsuperuser.py
@@ -6,8 +6,8 @@ import getpass
import sys
from optparse import make_option
+from django.contrib.auth import get_user_model
from django.contrib.auth.management import get_default_username
-from django.contrib.auth.models import get_user_model
from django.core import exceptions
from django.core.management.base import BaseCommand, CommandError
from django.db import DEFAULT_DB_ALIAS
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
index 62bf68afbc..6604423512 100644
--- a/django/contrib/auth/models.py
+++ b/django/contrib/auth/models.py
@@ -1,7 +1,6 @@
import re
import urllib
-from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import send_mail
from django.core import validators
@@ -271,12 +270,6 @@ class AbstractBaseUser(models.Model):
raise NotImplementedError()
-def get_user_model():
- "Return the User model that is active in this project"
- app_label, model_name = settings.AUTH_USER_MODEL.split('.')
- return models.get_model(app_label, model_name)
-
-
class User(AbstractBaseUser):
"""
Users within the Django authentication system are represented by this
diff --git a/django/contrib/auth/views.py b/django/contrib/auth/views.py
index c86ef53595..d32d2180b9 100644
--- a/django/contrib/auth/views.py
+++ b/django/contrib/auth/views.py
@@ -70,6 +70,7 @@ def login(request, template_name='registration/login.html',
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
def logout(request, next_page=None,
template_name='registration/logged_out.html',
redirect_field_name=REDIRECT_FIELD_NAME,
@@ -100,6 +101,7 @@ def logout(request, next_page=None,
# Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page or request.path)
+
def logout_then_login(request, login_url=None, current_app=None, extra_context=None):
"""
Logs out the user if he is logged in. Then redirects to the log-in page.
@@ -108,6 +110,7 @@ def logout_then_login(request, login_url=None, current_app=None, extra_context=N
login_url = settings.LOGIN_URL
return logout(request, login_url, current_app=current_app, extra_context=extra_context)
+
def redirect_to_login(next, login_url=None,
redirect_field_name=REDIRECT_FIELD_NAME):
"""
@@ -124,6 +127,7 @@ def redirect_to_login(next, login_url=None,
return HttpResponseRedirect(urlparse.urlunparse(login_url_parts))
+
# 4 views for password reset:
# - password_reset sends the mail
# - password_reset_done shows a success message for the above
@@ -169,6 +173,7 @@ def password_reset(request, is_admin_site=False,
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
def password_reset_done(request,
template_name='registration/password_reset_done.html',
current_app=None, extra_context=None):
@@ -178,6 +183,7 @@ def password_reset_done(request,
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
# Doesn't need csrf_protect since no-one can guess the URL
@sensitive_post_parameters()
@never_cache
@@ -191,7 +197,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
View that checks the hash in a password reset link and presents a
form for entering a new password.
"""
- assert uidb36 is not None and token is not None # checked by URLconf
+ assert uidb36 is not None and token is not None # checked by URLconf
if post_reset_redirect is None:
post_reset_redirect = reverse('django.contrib.auth.views.password_reset_complete')
try:
@@ -221,6 +227,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
def password_reset_complete(request,
template_name='registration/password_reset_complete.html',
current_app=None, extra_context=None):
@@ -232,6 +239,7 @@ def password_reset_complete(request,
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
@sensitive_post_parameters()
@csrf_protect
@login_required
@@ -257,6 +265,7 @@ def password_change(request,
return TemplateResponse(request, template_name, context,
current_app=current_app)
+
@login_required
def password_change_done(request,
template_name='registration/password_change_done.html',