RoutablePageMixin with breadcrumbs, aka: route-functions in Page tree

333 views
Skip to first unread message

Andreas Nüßlein

unread,
Jun 20, 2016, 8:22:32 AM6/20/16
to Wagtail support
Hey all,

so I have this Page, AkademiePage(RoutablePageMixin, Page), and it has a default route, as well as a list-route and a details-route.

class AkademiePage(RoutablePageMixin, Page):

@route(r'^$')
def base(self, request):
return TemplateResponse(
request,
self.get_template(request),
self.get_context(request)
)

@route(r'^seminare/$')
def seminare(self, request):
template = 'pages/seminar_overview_page.html'
context = super().get_context(request)
context['seminare'] = Seminar.objects.all()
return render(request, template, context)

@route(r'^seminare/(?P<id>[0-9]+)/$')
def seminar_detail(self, request, id):
return seminar_details(self, request, id)



To display breadcrumbs for this "structure", I will have to manually add them.
The route-functions don't define subpages that are children to AkademiePage, so I can't simply traverse via the self-object; I can't do: 
for child in page.get_ancestors(): ... for these routes/subpages.

And they don't have a hierarchy. 
In this case I'd obviously would want something like: Home > Akademie > Seminare > Seminar1. So I would define somewhat like a subpage-dict or object for seminare(self, request)as well as seminar_detail(self, request, id):.  Only seminar_detail will need 2 subpages. 

I could define SeminarePage but with SeminareDetailPage this will not work, since I need parameters there.

So the question is:
Does anybody have a nice solution? Could we upgrade the whole RoutablePageMixin to provide such functionality? But how would the tree-structure be defined? Or does anybody have a full-blown breadcrumbs-templatetag that can handle this situation?

Thanks

Andreas Nüßlein

unread,
Jun 20, 2016, 8:27:09 AM6/20/16
to Wagtail support
PS: The solution I used so far, but find incredibly hacky:

subpage = {
'title': seminar.name,
'url': page.url + page.reverse_subpage('details', args=(id,)),
'subpage': {'title': 'Edit', 'url': ''}
}
context['page'] = page
context['subpage'] = subpage

and respectively in my breadcrumbs.py I check if such a context['subtitle'] exists and iterate over it.

Robert Slotboom

unread,
Jun 20, 2016, 11:46:30 AM6/20/16
to Wagtail support
Hi Andreas,

Probably you use something from this post

Cheers,

– Robert

Andreas Nüßlein

unread,
Jun 23, 2016, 2:51:15 PM6/23/16
to Wagtail support
Hi Robert,

thank you for your reply. The issue I described led to a multiple day long conversation about Wagtail and Django and Pages and Views (and Class-Based Views) etc... at work.
It turned out that, at least in my case, I'm probably gonna go with something similar to what I had before and what you proposed. Something pragmatic and simple and hacky and not reusable but working.

Thanks again :)

Robert Slotboom

unread,
Jun 25, 2016, 5:57:28 AM6/25/16
to Wagtail support
Hi Andreas,

I agree Wagtail is breaking fundamental Django conventions...

FYI some additions to the posted code:

def get_route_items(self):
    page_url
= self.url
    route_items
= []
    event_classes
= [Lecture, Course, Tour]
   
for event in event_classes:
        title
= event._meta.verbose_name_plural.lower()
        route_items
.append(
           
{'title': title, 'url': '{0}{1}/'.format(page_url, title)}
       
)
   
for key, val in TargetGroup.CHOICES:
        title
= _('for {0}').format(val)
        url
= _('{0}for-{1}/').format(page_url, val)
        route_item
= {
           
'title': title,
           
'url': url,
           
'children': []
       
}
       
for event in event_classes:
            event_title
= event._meta.verbose_name_plural.lower()
            child_url
= '{0}{1}/'.format(url, event_title)
            route_item
['children'].append(
               
{'title': title, 'url': child_url}
           
)
        route_items
.append(route_item)
   
return route_items


def get_parent_urls(self):
    parent_urls = []
    if self.current_url:
        url_parts = list(filter(None, self.current_url.split('/')))
        parent = '/{0}/'.format(url_parts.pop(0)) if url_parts else None
        current = url_parts.pop() if url_parts else None
        if url_parts:
            for part in url_parts:
                parent = '{0}{1}/'.format(parent, part)
                parent_urls.append(parent)
    return parent_urls

def get_url(self, url_name, **kwargs):
    return self.url + self.reverse_subpage(url_name, **kwargs)

def get_redirect_url(self, url_name, **kwargs):
    return self.full_url + self.reverse_subpage(url_name, **kwargs)

@route(r'^$')
def about_events(self, request):
    self.event_model = None
    self.target_key = None
    self.current_url = self.get_url('about_events')
    context = self.get_context(request)
    return TemplateResponse(
        request,
        self.get_template(request),
        context
    )

""" other routes """


def get_context(self, request, *args, **kwargs):
    context = super().get_context(request)
    context.update({
        'current_url': self.current_url,
        'parent_urls': self.get_parent_urls(),
        **self.get_subcontext()
    })
      return context



As you can see, urls can be translated.



@register.inclusion_tag('cms/tags/main_menu.html', takes_context=True)
def primary_menu(context, calling_page=None):
    site
= context.get('current_site')
    parent_urls
= context.get('parent_urls', None)
    current_url
= context.get('current_url', None)
    home_page
= site.root_page
   
if home_page:
        menuitems
= home_page.get_children().specific().live().in_menu()
       
for menuitem in menuitems:
           
if hasattr(menuitem, 'menu_caption'):
                menuitem
.caption = menuitem.menu_caption
            menuitem
.active = calling_page.url.startswith(menuitem.url) if calling_page else False
            menuitem
.children = menuitem.get_children().specific().live().in_menu()
           
if hasattr(menuitem, 'get_route_items'):
                menuitem
.route_items = menuitem.get_route_items()
       
       
return {
           
'home_page': home_page,
           
'calling_page': calling_page,
           
'menuitems': menuitems,
           
'parent_urls': parent_urls,
           
'current_url': current_url,
           
'request': context['request'],
       
}




Routed_items are added to the menuitem if they are available.

{% load cms_core_tags wagtailcore_tags %}
{% spaceless %}
   
<div id='largemenu' class="top-bar show-for-large row collapse">
       
<div class='large-4 columns'><a class='icon-home' href='{% pageurl home_page %}'><span>{{ home_page.title }}</span></a>{{ calling_page }}</div>
       
{% if menuitems %}
           
<ul class="dropdown menu large-7 column" data-dropdown-menu>
               
{% for menuitem in menuitems %}
                   
{% if menuitem.depth == 1 and menuitem.children or menuitem.route_items %}
                       
<li{% if menuitem.active %} class='active'{% endif %}>
                           
<a href='{% pageurl menuitem %}'>{% if menuitem.caption %}{{ menuitem.caption|lower}}{% else %}{{ menuitem.title|lower }}{% endif %}</a>
                           
<ul class='menu vertical'>
                               
{% for child in  menuitem.children %}
                                   
<li{% if menuitem.active %} class='active'{% endif %}><a href="{% pageurl child %}">{% if child.menu_caption %}{{ child.menu_caption|lower}}{% else %}{{ child.title|lower }}{% endif %}</a></li>
                               
{% endfor %}
                               
{% for item in menuitem.route_items %}
                                   
<li{% if item.url in parent_urls or item.url == current_url %} class='active'{% endif %}><a href="{{ item.url }}">{{ item.title }}</a></li>
                               
{% endfor %}
                           
</ul>
                        </
li>
                   
{% else %}
                       
<li{% if menuitem.active %} class='active'{% endif %}>
                           
<a href='{% pageurl menuitem %}'>{{ menuitem.title }}</a>
                       
</li>
                    {% endif %}
                {% endfor %}
            </
ul>
       
{% endif %}
       
<div class='large-1 columns'><a href='' class='icon-search'><span>zoeken</span></a></div>
   
</div>
{% endspaceless %}


Items can be set to class='active'

This template is using foundation for sites b.t.w.




Have a nice weekend,
– Robert

Robert Slotboom

unread,
Jun 25, 2016, 6:00:45 AM6/25/16
to Wagtail support
The above template code is truncated..
I’ll try again.
Reply all
Reply to author
Forward
0 new messages