Data migration of image model
Asked Answered
D

1

5

Hi this is mostly a copy paste of a question asked in Google groups:

Thanks to Wagtail docs, I was able to understand how to build a custom image model, BUT, as I have a website with more than 500 contents, I don't want to mess the whole thing up with a bad data migration. In fact, I am not sure of which migration operation I should use here. I think that I should this one: https://docs.djangoproject.com/en/1.8/ref/migration-operations/#altermodeltable Can someone confirm this ?

Thanks a lot Regards

EDIT: provide some details about the migration

This is surely wagtail-specific, why I may have omitted some details. Sorry for that. And as I don't have much reputation, I can't provide more than 2 links a single post 😞

Delative answered 30/1, 2017 at 8:31 Comment(3)
No doubt your question didn't get answered in Google Groups because you haven't given nearly enough information. What are you trying to do? What is the migration for? Why would you think it would "mess the whole thing up"? – Nauseous
I just provided more details. Sorry if it's too wagtail-specific, I can remove other tags to avoid non wagtail-aware people be bothered by my question. – Delative
And by the way, here is why I "copy-pasted from Google groups": groups.google.com/forum/#!topic/wagtail/ZFkK_tjZj1Q One of the reason I didn't get any answer is because Wagtail's Google Group support channel was dropped by wagtail maintainers. – Delative
P
10

I recently did this same migration to my own customised model, however, we were not actively using Tags so I did not worry about transferring tags across. This migration does not delete the original Image database records as I wanted to keep them just in case.

Step 1 - Create Model app_name/models.py

from django.db import models
from wagtail.wagtailimages.models import (
    Image, AbstractImage, AbstractRendition)


class ExtendedImage(AbstractImage):
    caption = models.CharField(max_length=255, blank=True)

    admin_form_fields = Image.admin_form_fields + (
        'caption',
    )


class ExtendedRendition(AbstractRendition):
    image = models.ForeignKey(ExtendedImage, related_name='renditions')

    class Meta:
        unique_together = (
            ('image', 'filter_spec', 'focal_point_key'),
        )

Step 2 - Run Migrations Looks like you may have done this, it creates the customised model

  1. $python manage.py makemigrations
  2. $python manage.py migrate

Step 3 - Create Custom Data Migration

  1. $python manage.py makemigrations --empty app_name

  2. Edit that file as below (see comments inline)

```

from __future__ import unicode_literals

from django.db import migrations

# This only COPIES images from the existing model to the new one
# to reverse during testing - run
# ./manage.py migrate main 0036_auto_20170524_1811 (replace with file name of previous migration)


def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    wagtail_image_model = apps.get_model('wagtailimages', 'Image')
    extended_image_model = apps.get_model('main', 'ExtendedImage')
    db_alias = schema_editor.connection.alias
    # Get images
    images = wagtail_image_model.objects.using(db_alias).all()
    new_images = []
    for image in images:
        new_images.append(extended_image_model(
            id=image.id,
            title=image.title,
            file=image.file,
            width=image.width,
            height=image.height,
            created_at=image.created_at,
            focal_point_x=image.focal_point_x,
            focal_point_y=image.focal_point_y,
            focal_point_width=image.focal_point_width,
            focal_point_height=image.focal_point_height,
            file_size=image.file_size,
            # image=test_image.caption,
            collection=image.collection,
            # tags=image.tags, # does not copy over
            uploaded_by_user=image.uploaded_by_user,
        ))
    # Create images in new model
    extended_image_model.objects.using(db_alias).bulk_create(new_images)
    # Leave all images in previous model


def reverse_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    extended_image_model = apps.get_model('main', 'ExtendedImage')
    db_alias = schema_editor.connection.alias
    # Delete all images created in the new model
    extended_image_model.objects.using(db_alias).all().delete()


class Migration(migrations.Migration):

    dependencies = [
        ('main', '0036_auto_20170524_1811'), # Django will create this part
    ]

    operations = [
        migrations.RunPython(forwards_func, reverse_func),
    ]

```

Step 4 - Update Settings

WAGTAILIMAGES_IMAGE_MODEL = 'my_app.ExtendedImage'

Test this along the way and when you are ready you can delete the original image database rows if want.

** Note about Postgres One issue we ran into was Postgres did not like me migrating things to the primary key, we had to run a SQL query to reset the current key to the max + 1

Philter answered 26/5, 2017 at 14:43 Comment(1)
Hey ! Thanks a lot for you answer, it comes a bit late as I finally was able to use a different image model without needing to migrate the data. That is why I let this question unanswered as I finally didn't need anymore to migrate, but I will try your solution as soon as I need it, it seems very well explained ! – Delative

© 2022 - 2024 β€” McMap. All rights reserved.