Login

Decorating urlpatterns

Author:
miracle2k
Posted:
January 1, 2008
Language:
Python
Version:
.96
Tags:
urls views decorators urlpatterns
Score:
3 (after 7 ratings)

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.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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'),
)

More like this

  1. Decorating URL includes by cotton 5 years ago
  2. is_staff decorator by munhitsu 8 years ago
  3. Decorate every view in a url tree by sjzabel 4 years, 9 months ago
  4. @url decorator - getting rid of urlpatterns by southern_sun 9 years ago
  5. automatic urlpattern creator by sleytr 7 years ago

Comments

david_bgk (on January 2, 2008):
<p>Why don't you use directly decorators in urls?</p> <p>from foo.views import contact, imprint, add, edit</p> <pre>urlpatterns = patterns('', # unprotected views (r'^public/contact/$', contact), (r'^public/imprint/$', imprint), # protected views (r'^admin/add/$', login_required(add)), (r'^admin/edit/$', login_required(edit)), ) </pre>

#

miracle2k (on January 3, 2008):
<p>@david_bgk: It would break reverse(). </p> <p>Sure, I could name the patterns, and I have considered doing that from time to time, but so far I am not yet sure if I want to.</p>

#

timbroder (on February 5, 2010):
<p>if you want to user included url files, like so</p>
  • decorated_patterns('', control_access, (r'^comments/', include('django.contrib.comments.urls')), )
<p>modify decorated_patterns to be:</p> <p>def decorated_patterns(prefix, func, *args):</p> <pre>result = patterns(prefix, *args) if func: for p in result: if isinstance(p, RegexURLPattern): p.__class__ = DecoratedURLPattern p._decorate_with = func elif isinstance(p, RegexURLResolver): for pp in p._get_url_patterns(): if isinstance(pp, RegexURLPattern): pp.__class__ = DecoratedURLPattern pp._decorate_with = func return result </pre>

#

jeverling (on March 23, 2010):
<p>This snippet works great, and allows you to enforce some precondition for a large number of URLs in one go (when using the fix from comment 3.).</p> <p>If you add **kwargs to decorated_patterns, it also works with named patterns.</p> <p>In my opinion, this is extremely useful, and the snippet is greatly underrated.</p> <p>Thanks for sharing this!</p>

#

aehlke (on March 1, 2011):
<p>This is broken in Django 1.3.</p> <p>To fix it, replace the DecoratedURLPattern class with this:</p> <pre>class DecoratedURLPattern(RegexURLPattern): def resolve(self, *args, **kwargs): result = RegexURLPattern.resolve(self, *args, **kwargs) if result: result.func = self._decorate_with(result.func) return result </pre>

#

jeverling (on July 21, 2011):
<p>Thanks aehlke! :)</p>

#

aehlke (on October 13, 2013):
<p>Aaand to fix it with Django 1.6, replace _get_url_patterns() with url_patterns</p> <p>:) Oh the joys of maintenance.</p>

#

Please login first before commenting.