TLDR: Getting error: LookupError: No installed app with label 'wagtailimages'.
once the custom data migration is executed in wagtail which causes all tests to fail, as Django can't find the app after running the latest migration.
I needed to add a few custom fields to my image model in my wagtail installation that supports a Vue SPA.
I followed the guidelines in the docs here: http://docs.wagtail.io/en/v2.0/advanced_topics/images/custom_image_model.html
So, I created a custom image model along with custom rendition like this:
class CustomImage(AbstractImage):
alt_text = models.CharField(max_length=255, blank=True)
caption = models.CharField(max_length=255, blank=True)
admin_form_fields = Image.admin_form_fields + (
"alt_text",
"caption",
)
class CustomRendition(AbstractRendition):
image = models.ForeignKey(
CustomImage, on_delete=models.CASCADE, related_name="renditions"
)
class Meta:
unique_together = (
("image", "filter_spec", "focal_point_key"),
)
I also changed the WAGTAILIMAGES_IMAGE_MODEL
setting to point to my new model:
WAGTAILIMAGES_IMAGE_MODEL = "pages.CustomImage"
I wrote a data migration with the help of this blog post which refers to this StackOverflow discussion:
# Generated by Django 2.1.10 on 2020-01-15 09:03
from django.db import migrations, models
def forwards_func(apps, schema_editor):
wagtail_image_model = apps.get_model("wagtailimages", "Image")
custom_image_model = apps.get_model("pages", "CustomImage")
tagged_item_model = apps.get_model("taggit", "TaggedItem")
django_content_type = apps.get_model("contenttypes", "contenttype")
db_alias = schema_editor.connection.alias
# Get images stored in default wagtail image model
images = wagtail_image_model.objects.using(db_alias).all()
new_images = []
for image in images:
new_images.append(
custom_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,
collection=image.collection,
uploaded_by_user=image.uploaded_by_user,
)
)
# Create images in new model
custom_image_model.objects.using(db_alias).bulk_create(new_images)
# Leave all images in previous model untouched.
# Move tags from old image to new image model. Moving tags is
# a little different case. The lookup table taggit_taggeditem looks like this:
# id object_id content_type_id tag_id
# 1 1 10 1
# 2 1 10 2
# 3 1 10 3
# 4 1 10 4
# In our case, the object_id will be same for old and new image model
# objects. So, we have to only change the content_type_id
ct_custom_img_model, created = django_content_type.objects.using(
db_alias
).get_or_create(app_label="pages", model="customimage")
ct_wagtail_model = django_content_type.objects.using(db_alias).get(
app_label="wagtailimages", model="image"
)
tagged_item_model.objects.using(db_alias).filter(
content_type_id=ct_wagtail_model.id
).update(content_type_id=ct_custom_img_model.id)
def reverse_func(apps, schema_editor):
# We get the model from the versioned app registry;
custom_image_model = apps.get_model("pages", "CustomImage")
tagged_item_model = apps.get_model("taggit", "TaggedItem")
django_content_type = apps.get_model("contenttypes", "contenttype")
db_alias = schema_editor.connection.alias
# Move tags from new image model to old wagtail model
ct_extended_model = django_content_type.objects.using(db_alias).get(
app_label="pages", model="customimage"
)
ct_wagtail_model = django_content_type.objects.using(db_alias).get(
app_label="wagtailimages", model="image"
)
tagged_item_model.objects.using(db_alias).filter(
content_type_id=ct_extended_model.id
).update(content_type_id=ct_wagtail_model.id)
# Delete all images created in the new model
custom_image_model.objects.using(db_alias).all().delete()
class Migration(migrations.Migration):
dependencies = [
("pages", "0030_auto_20200115_0817"),
]
operations = [
migrations.RunPython(forwards_func, reverse_func),
]
The forward migrations work as expected to migrate all the data and work well when I tested these changes locally.
I tried to test my backward migration, and they also work fine.
However, if I try to get the old wagtailimages.Image
model in my reverse_func
function, it throws an error LookupError: No installed app with label 'wagtailimages'.
Although I actually wanted to delete the images from the old model just to perform cleanup, but due to this error, I thought that it is not that important and I can just move on.
Unfortunately, as soon as I pushed the code to CI, all my tests were failing as when this 31st migration which is a custom data migration is applied, Django seems to not find the wagtailimages
app at all.
I'm not sure what is the issue here. I've been trying to debug this issue for a while now but all my efforts were futile. I also didn't find anything related to this on the web which might help.
I've also tried to simplify my migration like not doing barely anything at all and just trying to fetch the model using Django's apps.get_model
. The forward migration works fine, but in reverse migration, it seems that wagtailimages
app just vanishes. I'm not sure why django.setup()
isn't able to load that app.
Can anyone help in this regard and provide me a pointer on where are things going sideways?