[英]prefetch_related for Authenticated user
我正在开发一个 django web 应用程序,我正在通过使用prefetch_related
和select_related
方法来最小化单个数据库的点击量,我的User
模型中有一个特定的方法可以从它。
def get_profile_info(self):
*fetch data from a couple of models*
然后我在我view
使用这种方法。
def profile(request):
profile_info = request.user.get_profile_info()
*rest of the view*
问题是,由于request.user
不是通过普通查询方法检索的,所以我不能在拉用户的同时使用prefetch_related
和select_related
,而且我找不到任何方法来检索相关数据以及该用户的模型。
有没有办法,比如说,覆盖用户模型的检索,以便我可以运行prefetch_related
和select_related
方法?
很抱歉这个 necroposting,但是这个主题非常重要并且存在非常简单的答案,只需为您的用户模型创建一个自定义管理器并使用select_related
覆盖get
方法,如下所示:
from django.contrib.auth.models import AbstractUser, UserManager
class CustomUserManager(UserManager):
def get(self, *args, **kwargs):
return super().select_related('<put fields that you want>').get(*args, **kwargs)
class CustomUser(AbstractUser):
...
objects = CustomUserManager()
现在,每当 Django 检索request.user
用户实例时,它都会使用这个管理器。 此外,您所有的CustomUser.objects.get()
查询也将选择指定的相关字段。
更精细的方法可能是使用自定义身份验证后端。 通过使用这种方法,人们将能够使用 UserModel.objects.get 而不会在其他代码段中使用此管理器时进行不必要的连接(.select_related()) 或 DB 查找(.prefetch_related())。
# auth_backends.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
UserModel = get_user_model()
class RelatedModelBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
try:
user = UserModel._default_manager.select_related(
... # Do your magic here
).prefetch_related(
... # Do your magic here
)
get(
**{UserModel.USERNAME_FIELD: username}
)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel._default_manager.select_related(
... # Do your magic here
).prefetch_related(
... # Do your magic here
).get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
现在我们需要将新后端添加到设置文件中, 在此处阅读有关自定义身份验证后端的更多信息。
# settings.py
...
AUTHENTICATION_BACKENDS = ['myproject.auth_backends.RelatedModelBackend']
...
您始终可以使用select_related
和prefetch_related
从数据库中重新获取用户。 如果select_related
和prefetch_related
保存了很多查询,那么额外的查询来获取用户是值得的。
def profile(request):
user = User.objects.select_related(
...
).prefetch_related(
...
).get(pk=request.user.pk)
请注意,根据视图,在这种情况下prefetch_related
可能不是很有用。 它会导致每个模型一个额外的查询,因此当您获取整个查询集的相关对象而不是单个对象时,它最有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.