Dan Swain
Dan Swain

Reputation: 3098

Override Wagtail Page.get_url()?

In an attempt to use only the Wagtail Page tree for the nav structure, I have declared the following so that a link can be rendered if desired rather than a page url:

class Node(Page):
  
    class Meta:
        verbose_name = 'Node (no content or link)'

    link = models.CharField(max_length=255, default='', blank='True', help_text='Optional.  Leave blank if serving as a parent page')

    content_panels = Page.content_panels + [
        FieldPanel('link')
    ]

    def get_url(self, **kwargs):
        if self.link != '':
            return self.link
        else:
            return super().get_url(self, **kwargs)

In the template I have tried both {{ item.url }} and {{ item.specific.url }} where item is an item in the page tree that is being iterated. The item's url as defined by Wagtail's Page.get_url() function is always rendered, and the def get_url() I've defined is never being executed.

I am aware of Wagtail Menus but was trying to not have another dependency in this project, so aside from whether or not the above is the best architecture, what am I missing in getting this to work?


To follow up here, I have followed these instructions, and on the class Node(Page) model I now have the following in place of def get_url:

def get_url_parts(self, *args, **kwargs):
    site_id, root_url, page_path = super().get_url_parts(*args, **kwargs)
    # return an alternative page_path if link has a value
    if self.link.strip() != '':
        page_path = self.link

    return site_id, root_url, page_path

I found that I still had to render the page urls with item.specific.get_url. item.url would not work.

Upvotes: 0

Views: 892

Answers (1)

gasman
gasman

Reputation: 25227

This happens because the url property on the Page model is defined by this line of code:

url = property(get_url)

i.e. define a property url that wraps a call to the get_url function as it existed at that moment when that line of code is run - namely, the default implementation of Page.get_url. Even if you override get_url on the Node model, the Node model's url property will still be pointing at the original definition.

If you add the line url = property(get_url) after your definition of get_url, or call {{ item.specific.get_url }} directly on your template, you should hopefully see the desired behaviour.

As per the docs, get_url_parts is the recommended method to override if you're setting up a custom URL scheme, as this contains the shared logic common to all the URL accessors (url, get_url, full_url, relative_url).

Upvotes: 1

Related Questions