Django admin prefetch content_type model
Я использовал панель инструментов отладки django, чтобы проанализировать, почему вызовы моей модели usermodel были такими болезненно медленными в админке django. Там я увидел, что у меня были сотни дублирующих обращений к модели content_type:
SELECT --- FROM "django_content_type" WHERE "django_content_type". "id" = 1 LIMIT 21 362 похожих запросов. Дублируется 4 раза.
Честно говоря, я не понимаю, откуда вообще берутся эти вызовы, но я хотел предварительно получить модель. Однако это, похоже, невозможно обычным способом, потому что между моделями нет ни ForeignKey, ни каких-либо других прямых отношений. Как я могу сократить эти 362 вызова content_type?
Это та пользовательская модель, о которой идет речь:
class User(AbstractBaseUser, PermissionsMixin):
"""
Base model for the user application
"""
USERNAME_FIELD = "email"
objects = UserManager()
username_validator = None
username = None
email = models.EmailField(_("email address"), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
first_name = models.CharField(max_length=150, blank=True)
last_name = models.CharField(max_length=150, blank=True)
title_of_person = models.ForeignKey(
TitleOfPerson, on_delete=models.CASCADE, blank=True, null=True
)
is_verified = models.BooleanField(default=False)
language = models.ForeignKey(
Language, blank=True, null=True, on_delete=models.SET_NULL
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = _("User")
verbose_name_plural = _("Users")
def __str__(self) -> str:
return self.email
Спасибо
В вашем классе UserAdmin добавьте UserCreationForm для вашей модели User.
Например,
from django.contrib.auth.admin import (
UserAdmin as BaseUserAdmin, UserChangeForm as BaseUserChangeForm,
UserCreationForm as BaseUserCreationForm
)
class UserChangeForm(BaseUserChangeForm):
class Meta:
model = User
fields = '__all__'
def clean_email(self):
data = self.cleaned_data.get('email')
return data.lower()
class UserAdmin(BaseUserAdmin):
form = UserChangeForm
... other fields...
Это должно решить вашу проблему с запросами.
Фактическая часть, устраняющая проблему:
В стандартном UserChangeForm, внутри __init__ метода, user_permissions queryset инициализируется с select_related оптимизацией.
class UserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_(
"Raw passwords are not stored, so there is no way to see this "
"user’s password, but you can change the password using "
'<a href="{}">this form</a>.'
),
)
class Meta:
model = User
fields = "__all__"
field_classes = {"username": UsernameField}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
password = self.fields.get("password")
if password:
password.help_text = password.help_text.format("../password/")
user_permissions = self.fields.get("user_permissions")
if user_permissions:
user_permissions.queryset =
user_permissions.queryset.select_related(
"content_type"
)