From d6efc9fc231d80545277395f708b19f0252d31a8 Mon Sep 17 00:00:00 2001 From: "petr.prikryl" Date: Wed, 14 Sep 2022 17:51:42 +0200 Subject: [PATCH] optimization of AttachmentInline preventing iteration over all attachments in database --- post_office/admin.py | 13 ++++----- .../migrations/0012_auto_20220914_1745.py | 28 +++++++++++++++++++ post_office/models.py | 5 ++-- post_office/settings.py | 5 ++-- 4 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 post_office/migrations/0012_auto_20220914_1745.py diff --git a/post_office/admin.py b/post_office/admin.py index 71e967ab..1dc75bd8 100644 --- a/post_office/admin.py +++ b/post_office/admin.py @@ -33,20 +33,16 @@ def get_message_preview(instance): class AttachmentInline(admin.StackedInline): model = Attachment.emails.through extra = 0 + autocomplete_fields = ["attachment"] def get_queryset(self, request): """ Exclude inlined attachments from queryset, because they usually have meaningless names and are displayed anyway. """ - queryset = super().get_queryset(request) - inlined_attachments = [ - a.id - for a in queryset - if isinstance(a.attachment.headers, dict) - and a.attachment.headers.get("Content-Disposition", "").startswith("inline") - ] - return queryset.exclude(id__in=inlined_attachments) + return super().get_queryset(request).exclude( + **{"attachment__headers__Content-Disposition__startswith": "inline"} + ) class LogInline(admin.TabularInline): @@ -314,6 +310,7 @@ def save_model(self, request, obj, form, change): class AttachmentAdmin(admin.ModelAdmin): list_display = ['name', 'file'] filter_horizontal = ['emails'] + search_fields = ["name"] admin.site.register(Email, EmailAdmin) diff --git a/post_office/migrations/0012_auto_20220914_1745.py b/post_office/migrations/0012_auto_20220914_1745.py new file mode 100644 index 00000000..9c997646 --- /dev/null +++ b/post_office/migrations/0012_auto_20220914_1745.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.15 on 2022-09-14 15:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("post_office", "0011_models_help_text"), + ] + + operations = [ + migrations.AlterField( + model_name="attachment", + name="headers", + field=models.JSONField(blank=True, null=True, verbose_name="Headers"), + ), + migrations.AlterField( + model_name="email", + name="context", + field=models.JSONField(blank=True, null=True, verbose_name="Context"), + ), + migrations.AlterField( + model_name="email", + name="headers", + field=models.JSONField(blank=True, null=True, verbose_name="Headers"), + ), + ] diff --git a/post_office/models.py b/post_office/models.py index d736d48e..dd7138e0 100644 --- a/post_office/models.py +++ b/post_office/models.py @@ -10,7 +10,6 @@ from django.utils.encoding import smart_str from django.utils.translation import pgettext_lazy, gettext_lazy as _ from django.utils import timezone -from jsonfield import JSONField from post_office import cache from post_office.fields import CommaSeparatedEmailField @@ -68,7 +67,7 @@ class Email(models.Model): help_text=_("Email won't be sent after this timestamp")) message_id = models.CharField("Message-ID", null=True, max_length=255, editable=False) number_of_retries = models.PositiveIntegerField(null=True, blank=True) - headers = JSONField(_('Headers'), blank=True, null=True) + headers = models.JSONField(_("Headers"), blank=True, null=True) template = models.ForeignKey('post_office.EmailTemplate', blank=True, null=True, verbose_name=_("Email template"), on_delete=models.CASCADE) @@ -316,7 +315,7 @@ class Attachment(models.Model): emails = models.ManyToManyField(Email, related_name='attachments', verbose_name=_('Emails')) mimetype = models.CharField(max_length=255, default='', blank=True) - headers = JSONField(_('Headers'), blank=True, null=True) + headers = models.JSONField(_("Headers"), blank=True, null=True) class Meta: app_label = 'post_office' diff --git a/post_office/settings.py b/post_office/settings.py index ae20d029..b92f1db1 100644 --- a/post_office/settings.py +++ b/post_office/settings.py @@ -124,6 +124,7 @@ def get_message_id_fqdn(): return get_config().get('MESSAGE_ID_FQDN', DNS_NAME) -CONTEXT_FIELD_CLASS = get_config().get('CONTEXT_FIELD_CLASS', - 'jsonfield.JSONField') +CONTEXT_FIELD_CLASS = get_config().get( + "CONTEXT_FIELD_CLASS", "django.db.models.JSONField" +) context_field_class = import_string(CONTEXT_FIELD_CLASS)