mirror of
https://github.com/suitenumerique/messages.git
synced 2026-08-17 21:25:41 +02:00
⚡️(admin) avoid N+1 queries in admin & slow lookups
This commit is contained in:
@@ -10,7 +10,7 @@ from django.contrib import admin, messages
|
||||
from django.contrib.auth import admin as auth_admin
|
||||
from django.core.files.storage import storages
|
||||
from django.db import transaction
|
||||
from django.db.models import JSONField, Q
|
||||
from django.db.models import Exists, JSONField, OuterRef, Q
|
||||
from django.http import HttpResponse, HttpResponseNotAllowed
|
||||
from django.shortcuts import redirect
|
||||
from django.template.response import TemplateResponse
|
||||
@@ -90,8 +90,13 @@ class RecipientDeliveryStatusFilter(admin.SimpleListFilter):
|
||||
"""Filter queryset by recipient delivery status."""
|
||||
if self.value():
|
||||
return queryset.filter(
|
||||
recipients__delivery_status=int(self.value())
|
||||
).distinct()
|
||||
Exists(
|
||||
models.MessageRecipient.objects.filter(
|
||||
message_id=OuterRef("pk"),
|
||||
delivery_status=int(self.value()),
|
||||
)
|
||||
)
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
@@ -303,6 +308,9 @@ class MailDomainAccessInline(admin.TabularInline):
|
||||
model = models.MailDomainAccess
|
||||
autocomplete_fields = ("user",)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).select_related("user")
|
||||
|
||||
|
||||
@admin.register(models.MailDomain)
|
||||
class MailDomainAdmin(admin.ModelAdmin):
|
||||
@@ -392,6 +400,9 @@ class MailboxAccessInline(admin.TabularInline):
|
||||
model = models.MailboxAccess
|
||||
autocomplete_fields = ("user",)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).select_related("user")
|
||||
|
||||
|
||||
@admin.register(models.Mailbox)
|
||||
class MailboxAdmin(admin.ModelAdmin):
|
||||
@@ -512,6 +523,7 @@ class ChannelAdmin(admin.ModelAdmin):
|
||||
"created_at",
|
||||
)
|
||||
list_filter = ("type", "scope_level", "created_at")
|
||||
list_select_related = ("mailbox", "maildomain", "user")
|
||||
search_fields = ("name", "type")
|
||||
readonly_fields = ("created_at", "updated_at", "last_used_at")
|
||||
autocomplete_fields = ("mailbox", "maildomain", "user")
|
||||
@@ -619,6 +631,7 @@ class MailboxAccessAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
|
||||
list_display = ("id", "mailbox", "user", "role")
|
||||
list_select_related = ("mailbox", "user")
|
||||
search_fields = ("mailbox__local_part", "mailbox__domain__name", "user__email")
|
||||
autocomplete_fields = ("mailbox", "user")
|
||||
|
||||
@@ -689,6 +702,7 @@ class ThreadAccessAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
|
||||
list_display = ("id", "thread", "mailbox", "role")
|
||||
list_select_related = ("thread", "mailbox")
|
||||
search_fields = (
|
||||
"thread__subject",
|
||||
"mailbox__local_part",
|
||||
@@ -760,6 +774,9 @@ class ThreadAccessInline(admin.TabularInline):
|
||||
autocomplete_fields = ("mailbox",)
|
||||
readonly_fields = ("read_at", "starred_at")
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).select_related("mailbox")
|
||||
|
||||
|
||||
class ThreadEventInline(admin.TabularInline):
|
||||
"""Inline class for the ThreadEvent model.
|
||||
@@ -788,6 +805,11 @@ class ThreadEventInline(admin.TabularInline):
|
||||
def has_add_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def get_queryset(self, request):
|
||||
return (
|
||||
super().get_queryset(request).select_related("author", "channel", "message")
|
||||
)
|
||||
|
||||
|
||||
class UserEventInline(admin.TabularInline):
|
||||
"""Inline class for the UserEvent model.
|
||||
@@ -813,6 +835,13 @@ class UserEventInline(admin.TabularInline):
|
||||
def has_add_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def get_queryset(self, request):
|
||||
return (
|
||||
super()
|
||||
.get_queryset(request)
|
||||
.select_related("user", "thread", "thread_event")
|
||||
)
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def _cleanup_thread_access_formset(formset):
|
||||
@@ -932,6 +961,9 @@ class ThreadAdmin(admin.ModelAdmin):
|
||||
return
|
||||
super().save_formset(request, form, formset, change)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).prefetch_related("labels")
|
||||
|
||||
list_display = (
|
||||
"id",
|
||||
"subject",
|
||||
@@ -1058,12 +1090,16 @@ class MessageRecipientInline(admin.TabularInline):
|
||||
"retry_count",
|
||||
)
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).select_related("contact")
|
||||
|
||||
|
||||
@admin.register(models.Attachment)
|
||||
class AttachmentAdmin(admin.ModelAdmin):
|
||||
"""Admin class for the Attachment model"""
|
||||
|
||||
list_display = ("id", "name", "mailbox", "message", "created_at")
|
||||
list_select_related = ("mailbox", "message")
|
||||
search_fields = ("name", "mailbox__local_part", "mailbox__domain__name")
|
||||
autocomplete_fields = ("mailbox",)
|
||||
raw_id_fields = ("blob", "message")
|
||||
@@ -1112,7 +1148,7 @@ class MessageAdmin(admin.ModelAdmin):
|
||||
change_list_template = "admin/core/message/change_list.html"
|
||||
change_form_template = "admin/core/message/change_form.html"
|
||||
raw_id_fields = ("thread", "blob", "draft_blob", "parent", "channel")
|
||||
autocomplete_fields = ("sender", "signature")
|
||||
autocomplete_fields = ("sender", "sender_user", "signature")
|
||||
readonly_fields = ("mime_id", "created_at", "updated_at")
|
||||
|
||||
def get_queryset(self, request):
|
||||
@@ -1283,6 +1319,7 @@ class ContactAdmin(admin.ModelAdmin):
|
||||
"""Admin class for the Contact model"""
|
||||
|
||||
list_display = ("id", "name", "email", "mailbox")
|
||||
list_select_related = ("mailbox",)
|
||||
ordering = ("-created_at", "email")
|
||||
search_fields = ("name", "email")
|
||||
autocomplete_fields = ("mailbox",)
|
||||
@@ -1332,6 +1369,7 @@ class LabelAdmin(admin.ModelAdmin):
|
||||
"parent_name",
|
||||
)
|
||||
search_fields = ("name", "mailbox__local_part", "mailbox__domain__name")
|
||||
list_select_related = ("mailbox",)
|
||||
readonly_fields = ("slug",)
|
||||
autocomplete_fields = ("mailbox",)
|
||||
raw_id_fields = ("threads",)
|
||||
@@ -1431,6 +1469,7 @@ class MailDomainAccessAdmin(admin.ModelAdmin):
|
||||
"""Admin class for the MailDomainAccess model"""
|
||||
|
||||
list_display = ("id", "maildomain", "user", "role")
|
||||
list_select_related = ("maildomain", "user")
|
||||
search_fields = ("maildomain__name", "user__email")
|
||||
list_filter = ("role",)
|
||||
autocomplete_fields = ("maildomain", "user")
|
||||
@@ -1451,6 +1490,7 @@ class DKIMKeyAdmin(admin.ModelAdmin):
|
||||
)
|
||||
search_fields = ("selector", "domain__name")
|
||||
list_filter = ("algorithm", "is_active")
|
||||
list_select_related = ("domain",)
|
||||
readonly_fields = ("public_key", "created_at", "updated_at")
|
||||
autocomplete_fields = ("domain",)
|
||||
fieldsets = (
|
||||
@@ -1536,6 +1576,7 @@ class MessageTemplateAdmin(admin.ModelAdmin):
|
||||
"is_default",
|
||||
"created_at",
|
||||
)
|
||||
list_select_related = ("mailbox", "maildomain")
|
||||
autocomplete_fields = ("mailbox", "maildomain")
|
||||
search_fields = ("name",)
|
||||
readonly_fields = (
|
||||
|
||||
@@ -2123,6 +2123,20 @@ class InboundMessage(BaseModel):
|
||||
class BlobManager(models.Manager):
|
||||
"""Custom Manager for Blob model."""
|
||||
|
||||
def get_queryset(self):
|
||||
"""Defer the rollback-safety ``_deprecated_*`` FKs.
|
||||
|
||||
The columns have already been dropped in some deployed databases
|
||||
but the model fields are intentionally retained for rollback
|
||||
(see ``_deprecated_mailbox`` / ``_deprecated_maildomain``). A
|
||||
default SELECT must not reference the missing columns.
|
||||
"""
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.defer("_deprecated_mailbox", "_deprecated_maildomain")
|
||||
)
|
||||
|
||||
def create_blob(
|
||||
self,
|
||||
content: bytes,
|
||||
|
||||
Reference in New Issue
Block a user