Reputation: 547
Let's say I have a model:
class BlogPost(Page):
date = models.DateField("Post date")
intro = models.CharField(max_length=250)
body = StreamField([
('paragraph', blocks.RichTextBlock()),
('image', ImageChooserBlock()),
('gallery', CarouselBlock()),
('video', EmbedBlock()),
])
...
And I would like to create multiple pages in the sidebar that relate to this model. I tried an approach like this:
class BlogPostAdmin(ModelAdmin):
model = BlogPost
...
class DraftPostAdmin(ModelAdmin):
model = BlogPost
#query for drafts
...
class ScheduledPostAdmin(ModelAdmin):
model = BlogPost
#query for scheduled posts
...
class BlogGroup(ModelAdminGroup):
menu_label = 'Blog'
items = (BookAdmin, AuthorAdmin, GenreAdmin)
...
modeladmin_register(BlogGroup)
But the issue is that all of the pages show model instances that match the queryset for the first ModelAdmin. What is the best way to go about implementing multiple menu items to manage different aspects of one model in Wagtail?
Upvotes: 1
Views: 958
Reputation: 11
I agree that ProxyModel
s are the most obvious route.
ModelAdmin.get_queryset()
can filter the ListView
and it's referenced in some of the answers. Add a method like this to your ModelAdmin
:
class DraftPostAdmin(ModelAdmin):
model = BlogPost
def get_queryset(self, request):
return super().get_queryset().filter(published_status='Draft')
Upvotes: 0
Reputation: 5196
Here is a slightly different approach, by overriding some of the methods on your BlogGroup
and using only a single BlogPostAdmin
you can get pretty far.
from wagtail.admin.menu import MenuItem
from wagtail.contrib.modeladmin.options import (
ModelAdmin, ModelAdminGroup, modeladmin_register)
from bakerydemo.blog.models import BlogPage
class ModelAdminQueryMenuItem(MenuItem):
# based on the `ModelAdminMenuItem` but extends the Wagtail Admin `MenuItem` directly.
def __init__(self, model_admin, order, query, label_append=''):
self.model_admin = model_admin
url = model_admin.url_helper.index_url + "?" + query
classnames = 'icon icon-%s' % model_admin.get_menu_icon()
super().__init__(
label=model_admin.get_menu_label() + label_append,
url=url,
classnames=classnames,
order=order
)
def is_shown(self, request):
return self.model_admin.permission_helper.user_can_list(request.user)
class BlogPageAdmin(ModelAdmin):
model = BlogPage
def get_menu_items(self, order=None):
# new class method that builds a list of menu_item(s)
menu_items = []
## build 'live only' (no unpublished changes) items
live_menu_item = ModelAdminQueryMenuItem(self, order or self.get_menu_order(), query='has_unpublished_changes=False', label_append=' (Live)')
menu_items.append(live_menu_item)
## build 'draft' items
draft_menu_item = ModelAdminQueryMenuItem(self, order or self.get_menu_order(), query='has_unpublished_changes=True', label_append=' (Draft)')
menu_items.append(draft_menu_item)
return menu_items
def get_queryset(self, request):
qs = super().get_queryset(request)
## read the request and modify the qs as needed if query param does not work easily
return qs
class BlogGroup(ModelAdminGroup):
menu_label = 'Blog'
items = (BlogPageAdmin, )
def get_submenu_items(self):
menu_items = []
item_order = 1
for modeladmin in self.modeladmin_instances:
menu_items = menu_items + modeladmin.get_menu_items(item_order)
item_order = len(menu_items) + 1
return menu_items
modeladmin_register(BlogGroup)
BlogPageAdmin
class, this will have a new method on it get_menu_items
(plural), which will return a list of Wagtail Menu Items.MenuItem
but we also add a user permissions helper, see the menus.py helper file within modeladmin. This provides us a way to customise the URL (adding url params) and the label, this can be modified as needed to get our sub-menu items presenting the way we want.get_menu_items
manually builds up ALL the menu items we want, we can customise anything here, including label and icon to show what you want, essentially though this just provides a way to pass in a custom query params string to the url that gets built up.Page
can be used without any code changes as they just get passed in as a Dict into our query. Below I have put all the possible values.get_queryset
and read the request params and update our query accordingly.BlogGroup
we override the get_submenu_items
to use the custom method get_menu_items
. Note that this assumes EACH model passed in to this group will have that method.Upvotes: 0
Reputation: 3108
Use a proxy model and then define an appropriate manager for each proxy model. I have this working in an existing Wagtail-based application where I define proxy models for various states of Memberships in a membership application. In my case the base model is Member
, but then I have CurrentMember
, NonCurrentMember
, etc. This comment and related discussion might also be of interest.
Upvotes: 3