Reversing ModelAdmin URLs

It’s sometimes useful to be able to derive the index (listing) or create URLs for a model along with the edit, delete or inspect URL for a specific object in a model you have registered via the modeladmin app.

Wagtail itself does this by instantiating each ModelAdmin class you have registered, and using the url_helper attribute of each instance to determine what these URLs are.

You can take a similar approach in your own code too, by creating a ModelAdmin instance yourself, and using its url_helper to determine URLs.

See below for some examples:

Getting the edit or delete or inspect URL for an object

In this example, we will provide a quick way to edit the Author that is linked to a blog post from the admin page listing menu. We have defined an AuthorModelAdmin class and registered it with Wagtail to allow Author objects to be administered via the admin area. The BlogPage model has an author field (a ForeignKey to the Author model) to allow a single author to be specified for each post.

# file: wagtail_hooks.py

from wagtail.admin.widgets import PageListingButton
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from wagtail import hooks

# Author & BlogPage model not shown in this example
from models import Author

# ensure our modeladmin is created
class AuthorModelAdmin(ModelAdmin):
    model = Author
    menu_order = 200

# Creating an instance of `AuthorModelAdmin`
author_modeladmin = AuthorModelAdmin()

@hooks.register('register_page_listing_buttons')
def add_author_edit_buttons(page, user, next_url=None):
    """
    For pages that have an author, add an additional button to the page listing,
    linking to the 'edit' page for that author.
    """
    author_id = getattr(page, 'author_id', None)
    if author_id:
        # the url helper will return something like: /admin/my-app/author/edit/2/
        author_edit_url = author_modeladmin.url_helper.get_action_url('edit', author_id)
        yield PageListingButton('Edit Author',  author_edit_url, priority=10)

modeladmin_register(AuthorModelAdmin)

As you can see from the example above, when using get_action_url() to generate object-specific URLs, the target object’s primary key value must be supplied so that it can be included in the resulting URL (for example "/admin/my-app/author/edit/2/"). The following object-specific action names are supported by get_action_url():

  • 'edit' Returns a URL for updating a specific object.

  • 'delete' Returns a URL for deleting a specific object.

  • 'inspect' Returns a URL for viewing details of a specific object.

    • NOTE: This will only work if inspect_view_enabled is set to True on your ModelAdmin class.

Note

If you are using string values as primary keys for you model, you may need to handle cases where the key contains characters that are not URL safe. Only alphanumerics ([0-9a-zA-Z]), or the following special characters are safe: $, -, _, ., +, !, *, ', (, ).

django.contrib.admin.utils.quote() can be used to safely encode these primary key values before passing them to get_action_url(). Failure to do this may result in Wagtail not being able to recognise the primary key when the URL is visited, resulting in 404 errors.

Getting the index or create URL for a model

There are URLs available for the model listing view (action is 'index') and the create model view (action is 'create'). Each of these has an equivalent shortcut available; url_helper.index_url and url_helper.create_url.

For example:

from .wagtail_hooks import AuthorModelAdmin

url_helper = AuthorModelAdmin().url_helper

index_url = url_helper.get_action_url('index')
# OR we can use the 'index_url' shortcut
also_index_url = url_helper.index_url # note: do not call this property as a function
# both will output /admin/my-app/author

create_url = url_helper.get_action_url('create')
# OR we can use the 'create_url' shortcut
also_create_url = url_helper.create_url # note: do not call this property as a function
# both will output /admin/my-app/author/create

Note

If you have registered a page type with modeladmin (for example BlogPage), and pages of that type can be added to more than one place in the page tree, when a user visits the create URL, they’ll be automatically redirected to another view to choose a parent for the new page. So, this isn’t something you need to check or cater for in your own code.

To customise url_helper behaviour, see ModelAdmin.url_helper_class.