Fixed #25966 -- Made get_user_model() work at import time.
This makes it equivalent to: `from django.contrib.auth.models import User`. Thanks Aymeric Augustin for the initial patch and Tim Graham for the review.
This commit is contained in:
parent
eb42d8d5d9
commit
cb7bbf97a7
|
@ -172,7 +172,7 @@ def get_user_model():
|
||||||
Returns the User model that is active in this project.
|
Returns the User model that is active in this project.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return django_apps.get_model(settings.AUTH_USER_MODEL)
|
return django_apps.get_model(settings.AUTH_USER_MODEL, require_ready=False)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
|
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
|
||||||
except LookupError:
|
except LookupError:
|
||||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import unicode_literals
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class ModelBackend(object):
|
class ModelBackend(object):
|
||||||
"""
|
"""
|
||||||
|
@ -10,7 +12,6 @@ class ModelBackend(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
def authenticate(self, request, username=None, password=None, **kwargs):
|
||||||
UserModel = get_user_model()
|
|
||||||
if username is None:
|
if username is None:
|
||||||
username = kwargs.get(UserModel.USERNAME_FIELD)
|
username = kwargs.get(UserModel.USERNAME_FIELD)
|
||||||
try:
|
try:
|
||||||
|
@ -97,7 +98,6 @@ class ModelBackend(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_user(self, user_id):
|
def get_user(self, user_id):
|
||||||
UserModel = get_user_model()
|
|
||||||
try:
|
try:
|
||||||
user = UserModel._default_manager.get(pk=user_id)
|
user = UserModel._default_manager.get(pk=user_id)
|
||||||
except UserModel.DoesNotExist:
|
except UserModel.DoesNotExist:
|
||||||
|
@ -139,8 +139,6 @@ class RemoteUserBackend(ModelBackend):
|
||||||
user = None
|
user = None
|
||||||
username = self.clean_username(remote_user)
|
username = self.clean_username(remote_user)
|
||||||
|
|
||||||
UserModel = get_user_model()
|
|
||||||
|
|
||||||
# Note that this could be accomplished in one try-except clause, but
|
# 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
|
# instead we use get_or_create when creating unknown users since it has
|
||||||
# built-in safeguards for multiple threads.
|
# built-in safeguards for multiple threads.
|
||||||
|
|
|
@ -22,6 +22,8 @@ from django.utils.safestring import mark_safe
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class ReadOnlyPasswordHashWidget(forms.Widget):
|
class ReadOnlyPasswordHashWidget(forms.Widget):
|
||||||
def render(self, name, value, attrs):
|
def render(self, name, value, attrs):
|
||||||
|
@ -179,7 +181,6 @@ class AuthenticationForm(forms.Form):
|
||||||
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Set the label for the "username" field.
|
# Set the label for the "username" field.
|
||||||
UserModel = get_user_model()
|
|
||||||
self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
|
self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
|
||||||
if self.fields['username'].label is None:
|
if self.fields['username'].label is None:
|
||||||
self.fields['username'].label = capfirst(self.username_field.verbose_name)
|
self.fields['username'].label = capfirst(self.username_field.verbose_name)
|
||||||
|
@ -254,7 +255,6 @@ class PasswordResetForm(forms.Form):
|
||||||
that prevent inactive users and users with unusable passwords from
|
that prevent inactive users and users with unusable passwords from
|
||||||
resetting their password.
|
resetting their password.
|
||||||
"""
|
"""
|
||||||
UserModel = get_user_model()
|
|
||||||
active_users = UserModel._default_manager.filter(**{
|
active_users = UserModel._default_manager.filter(**{
|
||||||
'%s__iexact' % UserModel.get_email_field_name(): email,
|
'%s__iexact' % UserModel.get_email_field_name(): email,
|
||||||
'is_active': True,
|
'is_active': True,
|
||||||
|
|
|
@ -2,6 +2,8 @@ from django import db
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
|
UserModel = auth.get_user_model()
|
||||||
|
|
||||||
|
|
||||||
def check_password(environ, username, password):
|
def check_password(environ, username, password):
|
||||||
"""
|
"""
|
||||||
|
@ -11,7 +13,6 @@ def check_password(environ, username, password):
|
||||||
on whether the user exists and authenticates.
|
on whether the user exists and authenticates.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
UserModel = auth.get_user_model()
|
|
||||||
# db connection state is managed similarly to the wsgi handler
|
# db connection state is managed similarly to the wsgi handler
|
||||||
# as mod_wsgi may call these functions outside of a request/response cycle
|
# as mod_wsgi may call these functions outside of a request/response cycle
|
||||||
db.reset_queries()
|
db.reset_queries()
|
||||||
|
@ -33,7 +34,6 @@ def groups_for_user(environ, username):
|
||||||
Authorizes a user based on groups
|
Authorizes a user based on groups
|
||||||
"""
|
"""
|
||||||
|
|
||||||
UserModel = auth.get_user_model()
|
|
||||||
db.reset_queries()
|
db.reset_queries()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -9,6 +9,8 @@ from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.db import DEFAULT_DB_ALIAS
|
from django.db import DEFAULT_DB_ALIAS
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Change a user's password for django.contrib.auth."
|
help = "Change a user's password for django.contrib.auth."
|
||||||
|
@ -38,8 +40,6 @@ class Command(BaseCommand):
|
||||||
else:
|
else:
|
||||||
username = getpass.getuser()
|
username = getpass.getuser()
|
||||||
|
|
||||||
UserModel = get_user_model()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
u = UserModel._default_manager.using(options['database']).get(**{
|
u = UserModel._default_manager.using(options['database']).get(**{
|
||||||
UserModel.USERNAME_FIELD: username
|
UserModel.USERNAME_FIELD: username
|
||||||
|
|
|
@ -31,6 +31,8 @@ from django.views.decorators.debug import sensitive_post_parameters
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.views.generic.edit import FormView
|
from django.views.generic.edit import FormView
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
def deprecate_current_app(func):
|
def deprecate_current_app(func):
|
||||||
"""
|
"""
|
||||||
|
@ -320,7 +322,6 @@ def password_reset_confirm(request, uidb64=None, token=None,
|
||||||
warnings.warn("The password_reset_confirm() view is superseded by the "
|
warnings.warn("The password_reset_confirm() view is superseded by the "
|
||||||
"class-based PasswordResetConfirmView().",
|
"class-based PasswordResetConfirmView().",
|
||||||
RemovedInDjango21Warning, stacklevel=2)
|
RemovedInDjango21Warning, stacklevel=2)
|
||||||
UserModel = get_user_model()
|
|
||||||
assert uidb64 is not None and token is not None # checked by URLconf
|
assert uidb64 is not None and token is not None # checked by URLconf
|
||||||
if post_reset_redirect is None:
|
if post_reset_redirect is None:
|
||||||
post_reset_redirect = reverse('password_reset_complete')
|
post_reset_redirect = reverse('password_reset_complete')
|
||||||
|
@ -453,7 +454,6 @@ class PasswordResetConfirmView(PasswordContextMixin, FormView):
|
||||||
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
|
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
|
||||||
|
|
||||||
def get_user(self, uidb64):
|
def get_user(self, uidb64):
|
||||||
UserModel = get_user_model()
|
|
||||||
try:
|
try:
|
||||||
# urlsafe_base64_decode() decodes to bytestring on Python 3
|
# urlsafe_base64_decode() decodes to bytestring on Python 3
|
||||||
uid = force_text(urlsafe_base64_decode(uidb64))
|
uid = force_text(urlsafe_base64_decode(uidb64))
|
||||||
|
|
|
@ -4,6 +4,7 @@ import time
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.signals import setting_changed
|
from django.core.signals import setting_changed
|
||||||
from django.db import connections, router
|
from django.db import connections, router
|
||||||
from django.db.utils import ConnectionRouter
|
from django.db.utils import ConnectionRouter
|
||||||
|
@ -172,3 +173,24 @@ def auth_password_validators_changed(**kwargs):
|
||||||
def user_model_swapped(**kwargs):
|
def user_model_swapped(**kwargs):
|
||||||
if kwargs['setting'] == 'AUTH_USER_MODEL':
|
if kwargs['setting'] == 'AUTH_USER_MODEL':
|
||||||
apps.clear_cache()
|
apps.clear_cache()
|
||||||
|
try:
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
UserModel = get_user_model()
|
||||||
|
except ImproperlyConfigured:
|
||||||
|
# Some tests set an invalid AUTH_USER_MODEL.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
from django.contrib.auth import backends
|
||||||
|
backends.UserModel = UserModel
|
||||||
|
|
||||||
|
from django.contrib.auth import forms
|
||||||
|
forms.UserModel = UserModel
|
||||||
|
|
||||||
|
from django.contrib.auth.handlers import modwsgi
|
||||||
|
modwsgi.UserModel = UserModel
|
||||||
|
|
||||||
|
from django.contrib.auth.management.commands import changepassword
|
||||||
|
changepassword.UserModel = UserModel
|
||||||
|
|
||||||
|
from django.contrib.auth import views
|
||||||
|
views.UserModel = UserModel
|
||||||
|
|
|
@ -473,10 +473,6 @@ Here are some common problems that you may encounter during initialization:
|
||||||
will also trigger this exception. The ORM cannot function properly until all
|
will also trigger this exception. The ORM cannot function properly until all
|
||||||
models are available.
|
models are available.
|
||||||
|
|
||||||
Another common culprit is :func:`django.contrib.auth.get_user_model()`. Use
|
|
||||||
the :setting:`AUTH_USER_MODEL` setting to reference the User model at import
|
|
||||||
time.
|
|
||||||
|
|
||||||
This exception also happens if you forget to call :func:`django.setup()` in
|
This exception also happens if you forget to call :func:`django.setup()` in
|
||||||
a standalone Python script.
|
a standalone Python script.
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,9 @@ Minor features
|
||||||
Set :attr:`CustomUser.EMAIL_FIELD
|
Set :attr:`CustomUser.EMAIL_FIELD
|
||||||
<django.contrib.auth.models.CustomUser.EMAIL_FIELD>` to the name of the field.
|
<django.contrib.auth.models.CustomUser.EMAIL_FIELD>` to the name of the field.
|
||||||
|
|
||||||
|
* :func:`~django.contrib.auth.get_user_model` can now be called at import time,
|
||||||
|
even in modules that define models.
|
||||||
|
|
||||||
:mod:`django.contrib.contenttypes`
|
:mod:`django.contrib.contenttypes`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -487,9 +487,33 @@ different user model.
|
||||||
|
|
||||||
post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
|
post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
|
||||||
|
|
||||||
Generally speaking, you should reference the user model with the
|
Generally speaking, it's easiest to refer to the user model with the
|
||||||
:setting:`AUTH_USER_MODEL` setting in code that is executed at import
|
:setting:`AUTH_USER_MODEL` setting in code that's executed at import time,
|
||||||
time. ``get_user_model()`` only works once Django has imported all models.
|
however, it's also possible to call ``get_user_model()`` while Django
|
||||||
|
is importing models, so you could use
|
||||||
|
``models.ForeignKey(get_user_model(), ...)``.
|
||||||
|
|
||||||
|
If your app is tested with multiple user models, using
|
||||||
|
``@override_settings(AUTH_USER_MODEL=...)`` for example, and you cache the
|
||||||
|
result of ``get_user_model()`` in a module-level variable, you may need to
|
||||||
|
listen to the :data:`~django.test.signals.setting_changed` signal to clear
|
||||||
|
the cache. For example::
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.core.signals import setting_changed
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
@receiver(setting_changed)
|
||||||
|
def user_model_swapped(**kwargs):
|
||||||
|
if kwargs['setting'] == 'AUTH_USER_MODEL':
|
||||||
|
apps.clear_cache()
|
||||||
|
from myapp import some_module
|
||||||
|
some_module.UserModel = get_user_model()
|
||||||
|
|
||||||
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
|
The ability to call ``get_user_model()`` at import time was added.
|
||||||
|
|
||||||
.. _specifying-custom-user-model:
|
.. _specifying-custom-user-model:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue