Django dynamic urls

nijansen picture nijansen · Feb 25, 2012 · Viewed 21.1k times · Source

I am developing a website using Django as the backend, and I want to allow the customer to add new pages using the admin interface - so he enters a page title, an page alias that is used for nicer urls, and chooses whether he wants static content or an article based structure.

My approach is the following: I have created an app called sitemanager that consists of the page model described above, and a context processor that adds the pages to the context of my templates (for menus, etc.) and this works fine.

Of course, I also need to hook it into my url-file, but here is where the trouble begins: I can, thanks to the pythonic structure of Django, retrieve the Page model within urls.py, and generate my url pattern accordingly, and it does show, but Django seems to cache that file (which makes sense usually), so changes will take place only after a server restart. This obviously is not acceptable.

My first idea would be somehow bringing the admin application to resetting the url cache if new pages are added, or deleted, or aliases are modified (and only then, because caching generally is a good thing), but I have no idea how to start there.

Or maybe there is also a simpler solution that I am not seeing at the moment?

The relevant part of my urls.py looks basically like this:

from sitemanager.models import Page
static_pages = Page.objects.filter(static=True)
article_pages = Page.objects.filter(static=False)
for page in static_pages:
    pattern = r'^/'+page.alias+'/$'
    urlpatterns += patterns('',
        url(pattern, 'views.static_page',
            { 'active': page }
        )
    )
# Pretty much the same for the article pages,
# but with includes of another app

I hope I didn't make too many mistakes while stripping that code in my head!

Answer

Mariusz Jamro picture Mariusz Jamro · Feb 25, 2012

You can use named groups in the urls to pass data to views and it won't require any dynamic updating in the urls. The named part containing page.alias will be simply passed as a keyword argument to your view function. You can use it to get the actual Page object.

# urls.py
urlpatterns += patterns('',
   (r'^(?P<page_alias>.+?)/$', 'views.static_page'),
)

# views.py
def static_page(request, page_alias):    # page_alias holds the part of the url
    try:
        active = Page.objects.get(page_alias=page_alias)
    except Page.DoesNotExist:
        raise Http404("Page does not exist")