Home > OS >  How to customize the admin form for a custom image model in Wagtail CMS?
How to customize the admin form for a custom image model in Wagtail CMS?

Time:12-03

I need to add a string based unique ID to Wagtail’s image model. These IDs are a relatively short combination of letters, numbers and punctuation, e.g. "AS.M-1.001". So I am using a custom image model with Django’s standard CharField for that with the argument unique=True. But the editing form unfortunately does not check if the ID is unique. So I can use the same ID for multiple images. This check for uniqueness does work in any other standard form in Wagtail, e.g. the Page model. But not for the image model.

from django.db import models
from wagtail.images.models import Image, AbstractImage

class CustomImage(AbstractImage):
    custom_id = models.CharField(max_length=32, unique=True, null=True, blank=True)
    admin_form_fields =  ( 'custom_id', )   Image.admin_form_fields

My approach would be to override the editing form with a custom one to display more warnings and errors, like you can do with base_form_class for Wagtail’s Page model etc., as documented here. I tried both wagtail.admin.forms.WagtailAdminModelForm as well as wagtail.images.forms.BaseImageForm.

from wagtail.images.forms import BaseImageForm
from wagtail.admin.forms import WagtailAdminModelForm

class CustomImageForm(WagtailAdminModelForm):
    # add more logic here
    pass

class CustomImage(ArtButlerIDMixin, AbstractImage):
    ...
    base_form_class = CustomImageForm

Both lead to the same exception:

raise AppRegistryNotReady("Models aren't loaded yet.")

So a tried to resort the apps in my settings with no effect. Does the standard approach how to override an admin form in Wagtail work for the image model at all? What could be other ways to get a unique string identifier working here? ... or to customize this form.

Solution (Update)

Following @gasman’s advice, I added the following line to my settings/base.py:

WAGTAILIMAGES_IMAGE_MODEL = 'images.CustomImage'
WAGTAILIMAGES_IMAGE_FORM_BASE = 'images.forms.CustomImageForm'  # NEW

And added a the following form to a forms.py in my images app:

from django.core.exceptions import ValidationError
from wagtail.images.forms import BaseImageForm
from .models import CustomImage

class CustomImageForm(BaseImageForm):

    def clean(self):
        cleaned_data = super().clean()
        custom_id = cleaned_data.get("custom_id")

        if CustomImage.objects.filter(custom_id=custom_id).exists():
            raise ValidationError(
                    "Custom ID already exists"
                )

        return cleaned_data

CodePudding user response:

Images in Wagtail don't use WagtailAdminModelForm or the base_form_class attribute - these are used by pages, snippets and ModelAdmin to support Wagtail-specific features like inline children and panels, but images work through plain Django models and forms.

You can customise the form by subclassing BaseImageForm and setting WAGTAILIMAGES_IMAGE_FORM_BASE in your project settings. As long as you define your form class somewhere outside of models.py (e.g. in a separate forms.py module), you'll avoid the circular dependency that leads to the "Models aren't loaded yet" error.

  • Related