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