1 | """
|
---|
2 | reversed urllookup tag
|
---|
3 |
|
---|
4 | Usage:
|
---|
5 | ---
|
---|
6 | {% load urlhelpers %}
|
---|
7 | {% url_for 'main.views.index' "request.method" request.path foo ok= "bar" method=request.method sub=9 %}
|
---|
8 | ---
|
---|
9 | The first parameter is the view the url will point to.
|
---|
10 | For the second and following parameters you can use named parameters like foo=bar.
|
---|
11 | Parameters and named parameters will be evaluated. If it doesn't evaluate then the string is used.
|
---|
12 | In the above example this means, assuming you use requestContext as your context, that
|
---|
13 | "request.method" => request.method
|
---|
14 | foo => foo
|
---|
15 | "bar" => bar
|
---|
16 | request.method => GET
|
---|
17 |
|
---|
18 | I'd be nice to have a middleware that prepopulated the named paramaters if they have already been given for a certain view
|
---|
19 |
|
---|
20 | If you copy/paste this code, be sure to remove references to logging, rclogging (request cycly logging if you wondered) is my homebrewn interface to python logging.
|
---|
21 | """
|
---|
22 |
|
---|
23 | from django.template import Library, Node, resolve_variable, TemplateSyntaxError
|
---|
24 | from django.core.urlresolvers import reverse_match
|
---|
25 | from django.db.models import get_model
|
---|
26 | from lib.rclogging import logger
|
---|
27 | import re
|
---|
28 |
|
---|
29 | register = Library()
|
---|
30 |
|
---|
31 |
|
---|
32 | def find_url_for_view(view , *args , **kwargs):
|
---|
33 | # url = reverse(view, *args , **kwargs )
|
---|
34 | # logger.debug(args)
|
---|
35 | # logger.debug(kwargs)
|
---|
36 |
|
---|
37 | match = reverse_match(view, args = args , kwargs = kwargs)
|
---|
38 | url = match.get_url()
|
---|
39 | logger.debug(match.get_unmatched_kwargs(kwargs))
|
---|
40 | logger.debug(match.get_default_args())
|
---|
41 | # logger.debug(re.split(r"[/.]" , url))
|
---|
42 |
|
---|
43 | # now i want to append a query string
|
---|
44 | # i want to use the unmatched kwargs for this
|
---|
45 | query_string = "&".join(["=".join([k, str(v)]) for k , v in match.get_unmatched_kwargs(kwargs).items()])
|
---|
46 | logger.debug(query_string)
|
---|
47 | if len(query_string) > 0:
|
---|
48 | query_string = "?" + query_string
|
---|
49 |
|
---|
50 | return url + query_string
|
---|
51 |
|
---|
52 | class ReversedUrlNode(Node):
|
---|
53 | def __init__(self , view , *args , **kwargs):
|
---|
54 | self.args = args
|
---|
55 | self.kwargs = kwargs
|
---|
56 | self.view = view
|
---|
57 |
|
---|
58 | def safe_resolve(self , var , context):
|
---|
59 | try:
|
---|
60 | outvar = resolve_variable(var , context)
|
---|
61 | except:
|
---|
62 | outvar = var
|
---|
63 | logger.debug("%s = %s" % (var ,outvar) )
|
---|
64 | return outvar
|
---|
65 |
|
---|
66 | def render(self , context):
|
---|
67 | args = [self.safe_resolve(v , context) for v in self.args]
|
---|
68 | kwargs = dict([(k, self.safe_resolve(v , context)) for k , v in self.kwargs.items()])
|
---|
69 | view = self.safe_resolve(self.view , context)
|
---|
70 | # try:
|
---|
71 | url = find_url_for_view(view , *args , **kwargs)
|
---|
72 | # except:
|
---|
73 | # logger.warn("reversed lookup did a booboo")
|
---|
74 | # url = "n/a"
|
---|
75 | # url = find_url_for_view(self.view , *args , **kwargs)
|
---|
76 | return url
|
---|
77 |
|
---|
78 | @register.tag()
|
---|
79 | def url_for(parser , token):
|
---|
80 | raw = re.sub(r'\s*=\s*' , "=" , token.contents)
|
---|
81 | # logger.debug(raw)
|
---|
82 | bits=raw.split()
|
---|
83 | if len(bits) < 2:
|
---|
84 | raise TemplateSyntaxError, "url_for need atleast one argument: url_for my.view"
|
---|
85 | args = []
|
---|
86 | kwargs = {}
|
---|
87 | view = bits[1]
|
---|
88 | for bit in bits[2:]:
|
---|
89 | pos_is = bit.find("=")
|
---|
90 | if pos_is == -1:
|
---|
91 | args.append(bit)
|
---|
92 | else:
|
---|
93 | kwargs[bit[:pos_is]] = bit[1+pos_is:]
|
---|
94 | # logger.debug("kwargs[%s] = %s" % (bit[:pos_is] , bit[1+pos_is:]))
|
---|
95 |
|
---|
96 | return ReversedUrlNode(view , *args , **kwargs)
|
---|