ddanier / django_url_alias

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

django_url_alias

About

django_url_alias allows you to completely rewrite certain URLs, if you need to. This is done for incoming URL handling (URL resolving) and outgoing URLs (via {% url … %} or resolve). URL rewrites are modular, so you may have static rewrites (like a dict in settings) and database based rewrites. You may even mix both types by having multiple URL rewriters.

How it works

django_url_alias provides a special ROOT_URLCONF which intercepts URL resolving on the lowest level. This way it can rewrite all incoming URLs, so other views will be resolved.

For outgoing URLs (to clarify: "outgoing" does only mean URLs generated by the system, these URLs still may be internal) The process is a little bit more complex. django_url_alias provides a special {% url %} template tag and its own version of reverse. If you use these, everything will just work fine. Sadly there is no sane way to just replace Django's default behaviour.

Usecase

Although Django's URL handling is really great there may be scanarios it just cannot handle. The flatpage app is one of the examples URL handling get weird if you need a catchall pattern. As this still works for flatpages you run into trouble when more then one app needs a similar mechanism (catchall pattern), as only the first one will be handled correctly (URL matches, further urlconf entries will be ignored).

Other frameworks / CMS / … often use a completely different way to accomplish great URL structure. Instead of having easy to read system / internal URLs they just put an abstraction layer above all URL handling. This means your blog entry (for example) may still have an ugly (internal) URL like "blog/entry/15". Now the new URL layer will take that ugly URL and allow the user or system to define aliases. An alias could for example rewrite "blog/entry/15" to just "my-trip-to-paris.html". On input URL handling this needs to be reversed, so the requested URL "my-trip-to-paris.html" will resolve to "blog/entry/15" again.

django_url_alias allows you to just do exactly this. As it does not provide any predefined rules / mechanisms for rewriting the URL you are free to use whatever rule you want. In theory you could even reuse the good old SlugField and regular expressions. Of course you may use a DB based mapping like so many systems use, too. Below you will find an example for flatpages, without the need for an catchall pattern.

Usage

Installation

  1. Get django_url_alias into your python sys.path (pip install django_url_alias)
  2. Replace settings.ROOT_URLCONF with "django_url_alias.urls"
  3. Put your old root urlconf into settings.URL_ALIAS_ROOT_URLCONF
  4. Define your URL rewriting modules using settings.URL_ALIAS_MODULES (see https://github.com/ddanier/django_url_alias/blob/master/example/example/url_aliases.py and example below)
  5. Put {% load url_alias %} into your templates, so {% url %} gets replaced
  6. Use django_url_alias.resolver.reverse in your Python code

About URL_ALIAS_MODULES

URL_ALIAS_MODULES is just a list of simple classes to rewrite the URLs Django handles or generates.

URL_ALIAS_MODULES = (
    'path.to.module.aliases.ExampleAliasModule',
)

Each class will be instantiated without any parameters and should provide two methods:

  • resolve(self, path): Change incoming URLs
  • reverse(self, path): Change outgoing URLs

A simple example may look like this:

class ExampleURLAliasModule(object):
    def resolve(self, path):
        if path == 'foo/':
            return 'bar/'

    def reverse(self, path):
        if path == 'bar/':
            return 'foo/'

Both methods must return nothing (/None) when no rewrite is done. The defined classes will be called in order for incoming and outgoing URLs. The first module which returns a replacement URL will shortcut further processing, thus will define the final URL.

Flatpage example

The flatpages app is in core, so it just gives an nice example. We don't want to use the catchall pattern any more. For this example to work you will need to go through installation first.

First of all we need to define our internal URL structure. This will not be visible to your visitors, although the internal URLs are still accessible.

urls.py:: python

urlpatterns = patterns('',
url(r'^flatpage/(?P<pk>[0-9]+)/$', 'example.views.flatpage', name='flatpage'),

)

Then the rewrite needs to be done, so flatpage.url will be used to present the external URL structure, while the internal ID-based URL gets used internally.

URL Rewrite module:: python

from django.contrib.flatpages.models import FlatPage import re

class FlatpagesURLAliasModule(object):

FLATPAGE_RE = re.compile('^/flatpage/(?P<pk>[0-9]+)/$')

def resolve(self, path):

path = '/' + path # we need a trailing slash for flatpages try:

flatpage = FlatPage.objects.get(url=path) return '/flatpage/%d/' % flatpage.pk
except FlatPage.DoesNotExist:
pass # just return nothing
def reverse(self, path):

match = self.FLATPAGE_RE.match(path) if match:

try:
flatpage = FlatPage.objects.get(pk=match.group('pk')) return flatpage.url
except FlatPage.DoesNotExist:
pass # just return nothing

Note: This is just an example. In an production envirionment you would need to a) check the sites relation and more importantly b) use some caching. The above code is very inefficient and should NEVER BE USED IN A PRODUCTION ENVIRIONMENT.

Advantages of implementation

  • request objects stay clean. You could rewrite URLs using middleware classes which fiddle with request.path_info, but this way you will loose information (or even worse: rewrite information).
  • Least obtrusive way of implementation.

Notes

  • You should define canonical tags, so internal URLs will not get indexed by search engines.

About

License:Other


Languages

Language:Python 100.0%