Skip to main content

wagtail-instance-selector

A widget for Wagtail's admin that allows you to create and select related items.

Features and screenshots

Customizable widget display

By default, widgets appear similar to other Wagtail elements, but they can be customised to include images and other items.

Item selection reuses the admin's list views to ensure consistent UIs with filtering.

Inline creation

Items can be created within the selection widget.

After creation, items can be selected from the success message or from the list view.

Installation

pip install wagtail-instance-selector

and add 'instance_selector' and 'wagtail_modeladmin' to INSTALLED_APPS.

If you're using Django 3+, you will need to change Django's iframe security flag in your settings:

X_FRAME_OPTIONS = 'SAMEORIGIN'

Documentation

Using the widget as a field panel

from django.db import models
from instance_selector.edit_handlers import InstanceSelectorPanel


class Shop(models.Model):
    pass


class Product(models.Model):
    shop = models.ForeignKey(Shop, on_delete=models.CASCADE)

    panels = [InstanceSelectorPanel("shop")]

Using the widget in a stream field

from django.db import models
from wagtail.admin.panels import FieldPanel
from wagtail.fields import StreamField
from instance_selector.blocks import InstanceSelectorBlock


class Product(models.Model):
    pass


class Service(models.Model):
    pass


class Shop(models.Model):
    content = StreamField([
        ("products", InstanceSelectorBlock(target_model="test_app.Product")),
        ("services", InstanceSelectorBlock(target_model="test_app.Service")),
    ], use_json_field=True)

    panels = [FieldPanel("content")]

To create reusable blocks, you can subclass InstanceSelectorBlock.

from instance_selector.blocks import InstanceSelectorBlock


class ProductBlock(InstanceSelectorBlock):
    def __init__(self, *args, **kwargs):
        target_model = kwargs.pop("target_model", "my_app.Product")
        super().__init__(target_model=target_model, **kwargs)

    class Meta:
        icon = "image"

# ...

StreamField([
    ("products", ProductBlock()),
])

Customizing the widget's display and behaviour

from wagtail_modeladmin.options import ModelAdmin, modeladmin_register
from instance_selector.registry import registry
from instance_selector.selectors import ModelAdminInstanceSelector
from .models import MyModel


@modeladmin_register
class MyModelAdmin(ModelAdmin):
    model = MyModel


class MyModelInstanceSelector(ModelAdminInstanceSelector):
    model_admin = MyModelAdmin()

    def get_instance_display_title(self, instance):
        if instance:
            return "some title"

    def get_instance_display_image_url(self, instance):
        if instance:
            return "/url/to/some/image.jpg"

    def get_instance_display_image_styles(self, instance):
        # The `style` properties set on the <img> element, primarily of use
        # to work within style+layout patterns
        if instance:
            return {
                'max-width': '165px',
                # ...
            }

    def get_instance_display_markup(self, instance):
        # Overriding this method allows you to completely control how the
        # widget will display the relation to this specific model
        return "<div> ... </div>"

    def get_instance_display_template(self):
        # The template used by `get_instance_display_markup`
        return "instance_selector/instance_selector_widget_display.html"

    def get_instance_selector_url(self):
        # The url that the widget will render within a modal. By default, this
        # is the ModelAdmin"s list view
        return "/url/to/some/view/"

    def get_instance_edit_url(self, instance):
        # The url that the user can edit the instance on. By default, this is
        # the ModelAdmin"s edit view
        if instance:
            return "/url/to/some/view/"


registry.register_instance_selector(MyModel, MyModelInstanceSelector())

Note that the ModelAdminInstanceSelector is designed for the common case. If your needs are more specific, you may find some use in instance_selector.selectors.BaseInstanceSelector.

Rationale & Credits

Largely, this is a rewrite of neon-jungle/wagtailmodelchooser that focuses on reusing the functionality in the ModelAdmins. We had started a large build using wagtailmodelchooser heavily, but quickly ran into UI problems when users needed to filter the objects or create them inline. After neon-jungle/wagtailmodelchooser#11 received little response, the decision was made to piece together parts from the ecosystem and replicate the flexibility of django's raw_id_fields, while preserving the polish in Wagtail's UI.

Much of this library was built atop of the work of others, specifically:

Development notes

Upgrading Wagtail versions

When upgrading this, ensure both InstanceSelectorPanel and InstanceSelectorBlock are tested manually via the example projects as they use different JavaScript integration approaches.

The example project is setup for testing via:

  • Shop model admin for InstanceSelectorBlock testing.
  • Product model admin InstanceSelectorPanel testing.

Run tests

pip install -r requirements.txt
python runtests.py

Linting and formatting

pip install -r requirements.txt
ruff check
ruff format

Metadata

Release files for wagtail-instance-selector 3.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wagtail-instance-selector 3.1.1
File Size Uploaded
wagtail_instance_selector-3.1.1.tar.gz 22.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wagtail-instance-selector 3.1.1
File Interpreter ABI Platform
wagtail_instance_selector-3.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 44.1 kB

Release files / wagtail_instance_selector-3.1.1.tar.gz

Download URL wagtail_instance_selector-3.1.1.tar.gz
Size 22.2 kB
Tags Source
SHA-256 checksum
How to use checksums
851918e9c496d0de15c7a2a407792779c260be16d56181c7da34e4919bbfe405
BLAKE2b-256 checksum
How to use checksums
7e477ff98fd5709a5b153c79e94e44bb96e15550630f0a36716a374957d0fff6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / wagtail_instance_selector-3.1.1-py3-none-any.whl

Download URL wagtail_instance_selector-3.1.1-py3-none-any.whl
Size 21.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fe5f2a2d2a7b874e9ae81ad6cb529d572f9779be328cc6b6fcce630c28dd4ce8
BLAKE2b-256 checksum
How to use checksums
e7e272beb97bec8ae1591c728338966d7e293f453ed29e91e6dae3f7f7c01850
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

3.1.1 This release

2 release files

3.1.0

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.1.2

3 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.2.1

2 release files

1.1.0

1 release file

1.0.1

1 release file

1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page