Search code examples
djangokeyerrorwagtail

How to use InlinePanel in ModelAdmin?


I'm setting up a model that needs to be created with a number of instances of a sub-model. I want to be able to edit and create this model in the admin interface so I'm adding it using ModelAdmin. According to the documentation I should be able to specify the fields/panels in accordance to normal Page types; however, when I add a InlinePanel I get an KeyError on the related field name.

models.py

class Application(models.Model):
    # other fields....

    panels = [MultiFieldPanel([
        FieldPanel('applicant'),
        FieldPanel('position'),
        FieldPanel('cover_letter'),
        FieldPanel('qualifications'),
        InlinePanel('references'),
        FieldPanel('draft'),
    ])]


class Reference(models.Model):

    application = models.ForeignKey(
        Application,
        related_name='references',
        on_delete=models.CASCADE,
        blank=False,
    )

    # other fields....

wagtails_hooks.py

class ApplicationAdmin(ModelAdmin):
    model = Application
    menu_icon = 'mail'
    menu_order = 400
    list_display = # other fields....

modeladmin_register(ApplicationAdmin)

Error

Request URL: http://127.0.0.1:8000/admin/involvement/application/create/

Django Version: 1.10.5

Exception Type: KeyError

Exception Value: 'references'

Exception Location: /[APPFOLDER]/venv/lib/python3.6/site-packages/wagtail/wagtailadmin/edit_handlers.py in init, line 627

I'm having trouble determining what I did wrong. Can anybody point me in the right direction?


Solution

  • Wagtail relies on the django-modelcluster library to allow the parent and child models to be handled in forms as a single unit. For this to work, the base Application model has to inherit from modelcluster.models.ClusterableModel (the Wagtail Page model does this as standard) and the child model has to be linked by a ParentalKey rather than a ForeignKey.

    Child models in an InlinePanel are also typically subclasses of Orderable, so they can be sorted; off the top of my head I can't remember whether this is an absolute requirement, or just a recommendation.

    from modelcluster.models import ClusterableModel
    
    class Application(ClusterableModel):
        # ...
    
    class Reference(Orderable):
        application = models.ParentalKey(
            Application,
            related_name='references',
            on_delete=models.CASCADE,
            blank=False,
        )