Login

url extension mechanism

Author:
showell
Posted:
April 16, 2009
Language:
Python
Version:
1.0
Tags:
url extend include
Score:
0 (after 0 ratings)

Executive summary: url "include" on steroids--granular extra parms and validate names in passing

We maintain multiple Django applications, and we use the excellent built-in include mechanism to allow one urls.py to borrow from another:

http://docs.djangoproject.com/en/dev/topics/http/urls/

If you scroll down to the section entitled "Passing extra options to include," you will see this annoying limitation:

''' Note that extra options will always be passed to every line in the included URLconf, regardless of whether the line's view actually accepts those options as valid. For this reason, this technique is only useful if you're certain that every view in the included URLconf accepts the extra options you're passing. '''

My snippet overcomes this limitation, allowing you to extend individual urls without polluting the namespace. The function also has the nice side effect of validating that the parent hasn't changed names on you.

 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from django.core.urlresolvers import RegexURLResolver

def extend(root_resolver, extra_parm_dct, require_matches=True):
    '''
        Extend a resolver to have extra parameters
        passed in by a per-name basis, and also
        validate that names exist so that child 
        application can essentially validate the API
        of the app whose urls it is including
        
        root_resolver: should be url w/include (see example below)
        extra_parm_dct:
            keys: should be names defined for reverse calls
            values: dictionaries of extra parameters to be sent to views
        require_matches: if True, raise exception if some names are not found
        
        Limitations: 
            1) only tested on python 2.5, django 1.1
            2) modifies resolvers directly, does not clone them

        Example usage:
            extend(url(r'', include('member.urls')),
                    {
                        'make_payment':
                            {'make_payment_form': QuickEnrollPaymentForm}, 
                        'home_page': {}, # simply must exist
                    }
                ),
            
    '''
    if not isinstance(root_resolver, RegexURLResolver):
        raise TypeError('Expected RegexURLResolver argument')
    names_to_extend = set(extra_parm_dct.keys())

    def _extend(resolver):
        for pattern in resolver.url_patterns:
            if isinstance(pattern, RegexURLResolver):
                _extend(pattern)
            else:
                name = pattern.name
                if name in extra_parm_dct:
                    extra_args = extra_parm_dct[name]
                    pattern.default_args.update(extra_args)
                    names_to_extend.discard(name)
    
    _extend(root_resolver)
    if require_matches and len(names_to_extend) > 0:
        raise Exception('The following names do not exist in extended urlconf: %s' % names_to_extend)
    return root_resolver
    

More like this

  1. Decorating URL includes by cotton 3 years, 8 months ago
  2. Format transition middleware by limodou 8 years, 1 month ago
  3. Partial templates, combine with and include by koblas 5 years ago
  4. Allow any view (probably a generic view) to accept POST variables into extra_context by orblivion 4 years, 6 months ago
  5. Url overrides and concurrent site versions by henrikv 8 years, 1 month ago

Comments

Please login first before commenting.