From 0b5fdda56893cbb012cfb2f1fb9ea292ba7cf4e7 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 --- .travis.yml | 6 ++-- README.md | 3 +- post_office/admin.py | 12 +++----- post_office/migrations/0001_initial.py | 5 ++-- .../migrations/0004_auto_20160607_0901.py | 5 ++-- .../migrations/0008_attachment_headers.py | 5 ++-- .../migrations/0012_auto_20220914_1745.py | 28 +++++++++++++++++++ post_office/models.py | 5 ++-- post_office/settings.py | 5 ++-- setup.py | 2 +- tox.ini | 2 -- 11 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 post_office/migrations/0012_auto_20220914_1745.py diff --git a/.travis.yml b/.travis.yml index d90e38bb..d3c9fed5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,15 +6,15 @@ matrix: include: # Python 3.7 - python: 3.7 - env: TOXENV=py37-django22,py37-django31,py37-django32,py37-django40 + env: TOXENV=py37-django31,py37-django32,py37-django40 # Python 3.8 - python: 3.8 - env: TOXENV=py38-django22,py38-django31,py38-django32,py38-django40 + env: TOXENV=py38-django31,py38-django32,py38-django40 # Python 3.9 - python: 3.9 - env: TOXENV=py39-django22,py39-django31,py39-django32,py39-django40 + env: TOXENV=py39-django31,py39-django32,py39-django40 # Django Master - python: 3.7 diff --git a/README.md b/README.md index b498f20c..ea701aad 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Django. Some awesome features are: ## Dependencies - [django \>= 2.2](https://djangoproject.com/) -- [jsonfield](https://github.com/rpkilby/jsonfield) - [bleach](https://bleach.readthedocs.io/) With this optional dependency, HTML emails are nicely rendered @@ -550,7 +549,7 @@ POST_OFFICE = { } ``` -`CONTEXT_FIELD_CLASS` defaults to `jsonfield.JSONField`. +`CONTEXT_FIELD_CLASS` defaults to `django.db.models.JSONField`. ### Logging diff --git a/post_office/admin.py b/post_office/admin.py index ce25c905..a1390b7b 100644 --- a/post_office/admin.py +++ b/post_office/admin.py @@ -17,7 +17,6 @@ from django.utils.translation import gettext_lazy as _ from .fields import CommaSeparatedEmailField -from .mail import send from .models import STATUS, Attachment, Email, EmailTemplate, Log from .sanitizer import clean_html @@ -34,6 +33,7 @@ class AttachmentInline(admin.StackedInline): model = Attachment.emails.through extra = 0 autocomplete_fields = ["attachment"] + parent_obj = None def get_formset(self, request, obj=None, **kwargs): self.parent_obj = obj @@ -48,13 +48,9 @@ def get_queryset(self, request): if self.parent_obj: queryset = queryset.filter(email=self.parent_obj) - 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 queryset.exclude( + **{"attachment__headers__Content-Disposition__startswith": "inline"} + ) class LogInline(admin.TabularInline): diff --git a/post_office/migrations/0001_initial.py b/post_office/migrations/0001_initial.py index 4ccf618e..84007827 100644 --- a/post_office/migrations/0001_initial.py +++ b/post_office/migrations/0001_initial.py @@ -1,5 +1,4 @@ from django.db import models, migrations -import jsonfield.fields import post_office.fields import post_office.validators import post_office.models @@ -38,8 +37,8 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(auto_now_add=True, db_index=True)), ('last_updated', models.DateTimeField(auto_now=True, db_index=True)), ('scheduled_time', models.DateTimeField(db_index=True, null=True, blank=True)), - ('headers', jsonfield.fields.JSONField(null=True, blank=True)), - ('context', jsonfield.fields.JSONField(null=True, blank=True)), + ('headers', models.TextField(null=True, blank=True)), + ('context', models.TextField(null=True, blank=True)), ], options={ }, diff --git a/post_office/migrations/0004_auto_20160607_0901.py b/post_office/migrations/0004_auto_20160607_0901.py index 0fd7f0bd..600f8722 100644 --- a/post_office/migrations/0004_auto_20160607_0901.py +++ b/post_office/migrations/0004_auto_20160607_0901.py @@ -1,7 +1,6 @@ # Generated by Django 1.9.6 on 2016-06-07 07:01 from django.db import migrations, models import django.db.models.deletion -import jsonfield.fields import post_office.models @@ -47,12 +46,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='email', name='context', - field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='Context'), + field=models.TextField(blank=True, null=True, verbose_name='Context'), ), migrations.AlterField( model_name='email', name='headers', - field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='Headers'), + field=models.TextField(blank=True, null=True, verbose_name='Headers'), ), migrations.AlterField( model_name='email', diff --git a/post_office/migrations/0008_attachment_headers.py b/post_office/migrations/0008_attachment_headers.py index 62b7251c..e2ee852f 100644 --- a/post_office/migrations/0008_attachment_headers.py +++ b/post_office/migrations/0008_attachment_headers.py @@ -1,6 +1,5 @@ # Generated by Django 1.11.16 on 2018-11-30 08:54 -from django.db import migrations -import jsonfield.fields +from django.db import models, migrations class Migration(migrations.Migration): @@ -13,6 +12,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='attachment', name='headers', - field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='Headers'), + field=models.TextField(blank=True, null=True, verbose_name='Headers'), ), ] 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) diff --git a/setup.py b/setup.py index fa0c7c43..fa9332fe 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ def run_tests(self): zip_safe=False, include_package_data=True, package_data={'': ['README.rst']}, - install_requires=['django>=2.2', 'jsonfield>=3.0', 'bleach', 'bleach[css]', 'pytz'], + install_requires=['django>=3.1', 'bleach', 'bleach[css]', 'pytz'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', diff --git a/tox.ini b/tox.ini index f6e6d128..b1925638 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,5 @@ [tox] envlist = - py{37,38,39}-django22 py{37,38,39}-django31 py{37,38,39}-django32 py{37,38,39}-django40 @@ -12,7 +11,6 @@ setenv = DJANGO_SETTINGS_MODULE=post_office.test_settings deps = - django22: Django<3 django31: Django<3.2 django32: Django<4.0 django40: Django<4.1