Add a filter_spec field on Rendition to track the filter spec string used

This is an initial step towards retiring Filter as a model (#2881). We
cannot go further than this in the present release, as we want to retain
the ability for developers with custom image models to use the Django
migration autodetector - this implies that all schema changes pertaining
to a Wagtail point release must happen in one go (there's no possibility
of applying a schema migration, then a data migration, then another schema
migration).
This commit is contained in:
Matt Westcott 2016-08-11 20:56:36 +01:00
parent b1d10db7f2
commit 690153c5b9
4 changed files with 83 additions and 1 deletions

View file

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-11 12:03
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wagtailimages', '0013_make_rendition_upload_callable'),
]
operations = [
migrations.AddField(
model_name='rendition',
name='filter_spec',
field=models.CharField(blank=True, db_index=True, max_length=255, null=True),
),
migrations.AlterField(
model_name='rendition',
name='filter',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailimages.Filter'),
),
]

View file

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10 on 2016-08-11 13:25
from __future__ import unicode_literals
from django.db import migrations
def fill_filter_spec_forward(apps, schema_editor):
# Populate Rendition.filter_spec with the spec string of the corresponding Filter object
Rendition = apps.get_model('wagtailimages', 'Rendition')
db_alias = schema_editor.connection.alias
for rendition in Rendition.objects.using(db_alias).select_related('filter'):
rendition.filter_spec = rendition.filter.spec
rendition.save()
def fill_filter_spec_reverse(apps, schema_editor):
# Populate the Rendition.filter
Rendition = apps.get_model('wagtailimages', 'Rendition')
Filter = apps.get_model('wagtailimages', 'Filter')
db_alias = schema_editor.connection.alias
filters_by_spec = {}
for rendition in Rendition.objects.using(db_alias):
try:
filter = filters_by_spec[rendition.filter_spec]
except KeyError:
filter, _ = Filter.objects.get_or_create(spec=rendition.filter_spec)
filters_by_spec[rendition.filter_spec] = filter
rendition.filter = filter
rendition.save()
class Migration(migrations.Migration):
dependencies = [
('wagtailimages', '0014_add_filter_spec_field'),
]
operations = [
migrations.RunPython(fill_filter_spec_forward, fill_filter_spec_reverse),
]

View file

@ -458,7 +458,8 @@ class Filter(models.Model):
class AbstractRendition(models.Model):
filter = models.ForeignKey(Filter, related_name='+')
filter = models.ForeignKey(Filter, related_name='+', null=True, blank=True)
filter_spec = models.CharField(max_length=255, db_index=True, null=True, blank=True)
file = models.ImageField(upload_to=get_rendition_upload_to, width_field='width', height_field='height')
width = models.IntegerField(editable=False)
height = models.IntegerField(editable=False)
@ -505,6 +506,12 @@ class AbstractRendition(models.Model):
filename = self.file.field.storage.get_valid_name(filename)
return os.path.join(folder_name, filename)
def save(self, *args, **kwargs):
# populate the `filter_spec` field with the spec string of the filter. In Wagtail 1.8
# Filter will be dropped as a model, and lookups will be done based on this string instead
self.filter_spec = self.filter.spec
return super(AbstractRendition, self).save(*args, **kwargs)
class Meta:
abstract = True

View file

@ -207,6 +207,12 @@ class TestRenditions(TestCase):
self.assertEqual(rendition.width, 400)
self.assertEqual(rendition.height, 300)
# check that the rendition has been recorded under the correct filter,
# via both the Rendition.filter_spec attribute (which will come into action
# in Wagtail 1.8) and the linked Filter model (which will be retired in 1.8)
self.assertEqual(rendition.filter_spec, 'width-400')
self.assertEqual(rendition.filter.spec, 'width-400')
def test_resize_to_max(self):
rendition = self.image.get_rendition('max-100x100')