Reverse wagtail URLs from non-wagtail views

1,676 views
Skip to first unread message

Scot Hacker

unread,
Aug 14, 2015, 2:10:06 PM8/14/15
to Wagtail support
In a site that mixes wagtail and standard Django views, I'd like to do the equivalent of reversing named URLs from a standard Django view, e.g.:


    if request.user.is_authenticated():
       
# Logged in user never needs to see the homepage
       
return HttpResponseRedirect(reverse('dashboard'))


where "dashboard" is a wagtail page. I tried experimenting with various wagtail URL helpers, but they all seem to expect an existing wagtail context. Is there a way to do this? Or do I need to hard-code such WT URLs into my non-WT views?

Thanks.


Matthew Westcott

unread,
Aug 15, 2015, 12:42:01 PM8/15/15
to wag...@googlegroups.com
Hi Scot,
We don't have anything like that at the moment - the nearest thing would be the {% slugurl %} tag, which is presumably one of the ones you've tried.

Personally, I'd argue that hard-coding the page URL *is* the correct way. Whatever approach you take here, you need something to serve as a persistent identifier for the page. There are various possibilities such as the page ID, or the slug, but they're all brittle in their own way - there's a tacit assumption that the page in question is not going to be moved, renamed or deleted. So why not take the simplest possible option, and make the URL that identifier? If your page is integral enough to your site that it's being referenced in templates, you shouldn't really ever be changing that URL anyhow, as a matter of good practice.

Cheers,
- Matt

Tim Heap

unread,
Aug 16, 2015, 7:58:33 PM8/16/15
to wag...@googlegroups.com
Hi Scot,

I've used wagtailsettings for this kind of thing in the past: https://pypi.python.org/pypi/wagtailsettings

It allows you to create a model to store various configuration things in the database, and integrates with the Wagtail admin for editing. An example in the documentation shows how you could use this in your exact situation, with a settings model that defines each key wagtail page in your application that Django might have to refer to: https://wagtailsettings.readthedocs.org/en/latest/settings.html#edit-handlers

from wagtailsettings import BaseSetting, register_setting

@register_setting
class KeyPageSettings(BaseSetting):
    dashboard_page = models.ForeignKey('wagtailcore.Page', on_delete=models.SET_NULL, null=True, blank=False)

    panels = [
        PageChooserPanel('dashboard_page'),
    ]

In your view code, you could do then something like:

if request.user.is_authenticated():
    key_pages = KeyPageSettings.for_site(request.site)
    return HttpResponseRedirect(key_pages.dashboard_page.url)

This means that you do not have to hard code the URL or slug of any page in your site, and then hope that it exists. The code is self documenting, as it is clear that you are redirecting users to the dashboard page, which is a Wagtail page, not a regular Django view.

--
You received this message because you are subscribed to the Google Groups "Wagtail support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wagtail+u...@googlegroups.com.
To post to this group, send an email to wag...@googlegroups.com.
Visit this group at http://groups.google.com/group/wagtail.
To view this discussion on the web, visit https://groups.google.com/d/msgid/wagtail/F31D5103-16BF-4146-8232-544852E6FD7E%40torchbox.com.
For more options, visit https://groups.google.com/d/optout.

Scot Hacker

unread,
Aug 17, 2015, 2:17:07 PM8/17/15
to Wagtail support
Interesting discussion, thanks guys. Just a bit of a mental shift, getting used to the idea of URLs being defined in the db rather than in code. At the end of the day, Matthew is right that URLs shouldn't change - I guess I'm trying to solve a non-existent problem out of habitual adherence to DRY. Mostly  just wondered if I was missing something. 

Related: I often use the `./manage.py show_urls` command bundled with Django Command Extensions to show all known URLs in a project. But of course it only knows about URLs defined in code, not in the db. Does wagtail provide a way to spit out all known URLs on the command line? Or could I write a management command that did that? 

Tim, thanks for the tip on wagtailsettings - that's cool to know about and will probably be useful for other aspects of this project.

./s

Scot Hacker

unread,
Aug 17, 2015, 2:59:45 PM8/17/15
to Wagtail support


On Monday, August 17, 2015 at 11:17:07 AM UTC-7, Scot Hacker wrote:

Related: I often use the `./manage.py show_urls` command bundled with Django Command Extensions to show all known URLs in a project. But of course it only knows about URLs defined in code, not in the db. Does wagtail provide a way to spit out all known URLs on the command line? Or could I write a management command that did that? 


Oh, NM, I see how it works. Cool!



>>> root = Page.objects.get(id=1)

>>> pages = root.get_descendants()

>>> for p in pages:
...   print(p, p.url)





Brett Grace

unread,
Aug 18, 2015, 11:14:29 AM8/18/15
to Wagtail support
For pages like a "dashboard", HomePage, blog index page, where I know that There Can Be Only One, I usually just define a specific type for that page. Then I can reference it explicitly, and even provide a template tag to get the URL:

@register.simple_tag(takes_context=False)
def training_homepage_link():
   
return TrainingHomePage.objects.get().url

This, of course, will blow up if more than one such page is in the system. In order to preserve the invariant that there can only be one such page, I prevent the creation of new such pages through admin interface. For example, the TrainingHomePage used in this example looks like this:

class TrainingHomePage(MultiPartable, Page):
    body
= RichTextField()

    parent_page_types
= []
    subpage_types
= []

That way, it never shows up as an option in the admin interface.

For cases where there can be more than one such instance, I use a variation on this technique to define important points a site's navigation hierarchy. For example, in the same site I define a "ServiceCategoryPage". The user can create as many categories as they like, but they have to be children of the ServiceHomePage (of which, there can be only one). Then when I need to build a menu I can just query for the DB for all live ServiceCategoryPages. The production site I'm using these examples from is https://www.dademoeller.com — it's pretty complicated, but there are no hard-coded or configuration-based URLs, it's all dynamic based on the DB. (This wasn't a design goal or anything, I just realized that it worked out that way as I was typing up this response.)

Reply all
Reply to author
Forward
0 new messages