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.