Decorating urlpatterns

One thing I wanted for a while was the ability to basically apply something like @login_required to a bunch of urlpatterns in one go, instead of having to decorate each and every view manually. I finally spent some time looking through the Django source, and I came up with the following:

from django.core.urlresolvers import RegexURLPattern
from django.conf.urls.defaults import patterns

class DecoratedURLPattern(RegexURLPattern):
    def resolve(self, *args, **kwargs):
        result = RegexURLPattern.resolve(self, *args, **kwargs)
        if result:
            result = list(result)
            result[0] = self._decorate_with(result[0])
        return result

def decorated_patterns(prefix, func, *args):
    result = patterns(prefix, *args)
    if func:
        for p in result:
            if isinstance(p, RegexURLPattern):
                p.__class__ = DecoratedURLPattern
                p._decorate_with = func
    return result

def control_access(view_func):
    def _checklogin(request, *args, **kwargs):
        raise Http404()
    return _checklogin

urlpatterns = patterns('views',
    # unprotected views
    (r'^public/contact/$',      'contact'),
    (r'^public/imprint/$',        'imprint'),
) + decorated_patterns('views', control_access,
    (r'^admin/add/$',      'add'),
    (r'^admin/edit/$',      'edit'),
)

In this example, the latter two views will always raise a 404.

So far it seems to work quite nicely.

5 Responses to “Decorating urlpatterns”

  1. Empty Says:

    Nice approach. Did you happen to see my Tip of the Week on using the auth decorators for generic views? You can apply the same thing to any view really.

    http://blog.michaeltrier.com/2007/12/17/this-week-in-django-2-2007-12-16

    Keep up the good work.

  2. admin Says:

    I did actually. It's a good idea, and for some reason I hadn't even thought about approaching it like that. Although in my case, it would break the ability to use reverse() without explicitly naming the patterns, which is something I am relying on for now.

    Of course if you're using generic views, then that won't be an issue.

  3. Subsume Says:

    Would be nice if this were extended to allow not only for RegexURLPatterns but also RegexURLResolvers e.g. include('app.urls'). Just a thought. Trying to extend it myself.

    I don't quite have it. Maybe you can provide a tip?

    http://dpaste.com/56910/

  4. Subsume Says:

    http://dpaste.com/56911/ <-- woops. Forgot.

  5. admin Says:

    I think you're doing it right. The only mistake I can see right now is that you're checking twice for RegexURLPattern:

    ``if isinstance(p, RegexURLPattern)`` instead of ``if isinstance(p, RegexURLResolver)``

Leave a Reply