django-selector

Django-Selector is a custom url pattern parser for Django whose API is based on Luke Arno’s Selector for WSGI. It is designed to simplify the writing and reading of url patterns by providing recipes for frequently used patterns. Django-Selector’s parser ignores classic regex based url patterns, so if you require the flexibility of regexes you needn’t jump through registration hoops for a one-off url pattern. Using these named patterns in your urls.py clarifies what they are matching as well as how they are matching it:

patterns('foo.views',
    (r'^/(?P<name>[a-zA-Z0-9\-]+)/(?P<foos>\d*.?\d+)/$', 'index', {}, 'foo-index'))

becomes:

parser.patterns('foo.views',
    (r'/{name:slug}/{foos:number}/', 'index', {}, 'foo-index'))

You can install django-selector with pip:

pip install django-selector

You can fork django-selector from its hg repository:

hg clone http://dev.jmoiron.net/hg/django-selector

Usage

Here’s an example of how a urls.py file might look when using django-selector:

from django.contrib import admin
from django.conf import settings
import dselector

admin.autodiscover()

parser = dselector.Parser()
urlpatterns = parser.patterns('',
    (r'admin/(.*)!', admin.site.root),
)
urlpatterns += parser.patterns('myblog',
    (r'blog/{page:digits}/', 'list', {}, 'blog-list'),
    (r'blog/{slug:slug}/', 'detail', {}, 'blog-detail'),
    (r'archive/{year:year}/', 'archive', {}, 'blog-year'),
    (r'archive/{year:year}/{month:month}/', 'archive', {}, 'blog-month'),
    (r'archive/{year:year}/{month:month}/{day:day}/', 'archive', {}, 'blog-day'),
    (r'comment/post/{content_type:slug}/{id:digits}/', 'comment_post', {}, 'comment-post'),
)

if settings.DEBUG:
    urlpatterns += parser.patterns('django.views.static',
        r('media/{path:any}', 'serve', {'document_root' : './media/'}),
    )

The primary way of denoting url parts with django-selector’s parser is via the named patterns syntax: {name:pattern}. This is parsed into a regular expression looking roughly like:

'(?P<name>%s)' % (pattern_definition)

Refer to the List of builtin named patterns for a description of all default patterns. You may optionally leave out the pattern, which will match against the segment pattern:

(r'archive/{year}/{month:month}/{day}/', archive, {}, 'blog-day')

Beyond these preprocessing steps, django-selector’s parser.patterns operates as the standard django.conf.urls.defaults.patterns.

Autowrapping

In addition to translating the shorthand named-pattern syntax to regex, django-selector bookends your string with ^ and $, as these are so often required that it is often cleaner to assume they are implied. When including another module’s patterns (as in the admin example above), you may cancel the automatic $ by adding a bang (!). If for you need a literal bang at the end of your url pattern, you may use !!, but in this case you will not get the autowrapped $.

New in django-selector 0.3

Because django-selector happily ignores regular expressions and only translates the named patterns it finds in the URL, it can be backwards compatible with django’s default url and url formats. However, because of the inescapable autowrapping, previous versions were not. Versions >= 0.3 will now automatically avoid autowrapping any pattern that either starts with a ^ or ends with a $.

This buys the default operation a lot of backwards compatibility, but still fails urls that are open-ended and lack a ^ at the begining. To achieve full backwards compatibility create your Parser with autowrap=False:

parser = dselector.Parser(autowrap=False)

Or add this setting to your settings.py:

SELECTOR_AUTOWRAP=False
class dselector.Parser(autowrap=None, **extra_patterns)

A parser that can process url patterns with named patterns in them.

autowrap defaults to True. When it’s False, autowrapping of patterns with ^ and $ is disabled, and django-selector’s parser should be backwards compatible with regular django url definitions. You can set the default autowrap value with settings.SELECTOR_AUTOWRAP.

Parser.patterns(prefix, *args)
A replacement ‘patterns’ that understands named patterns.
Parser.url(regex, view, kwargs=None, name=None, prefix='')
A replacement for ‘url’ that understands named patterns.

Defining your own named patterns

You can define your own named patterns for use in your parser in two ways:

  • you can initialize a parser with kwargs Parser(name=pattern, ...)
  • you can add patterns to a parser with Parser.register(name, pattern)
Parser.register(name, regex)
Registers a new pattern or overrides an old one.

List of builtin named patterns

name regex description
word r'\w+' a single word
alpha r'[a-zA-Z]+' alphabetic characters
digits r'\d+' digits
number r'\d*\.?\d+' float or integer numbers
chunk r'[^/^.]+' a ‘chunk’ of text (no /, ^, or .)
segment r'[^/]+' a url segment (between /’s)
any r'.*' anything; good for paths
year r'\d{4}' a 4 digit number
month r'(%s)' % '|'.join(months) textual abbreviated months (Jan, Feb, etc)
day r'\d{1,2}' a one or two digit number
slug r'[a-zA-Z0-9\-]+' suitable for a “slug field”

Note that the default month pattern uses the locale-aware calendar module. If you want to force a certain locale’s months, you should either set that locale or re-assign month in your parser via Parser.register.

Table Of Contents

This Page