X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/a78ab01230384bac5d762e91a41cc62e87f69f02..ee5fbe5df5817578911fbf0c2e1fc2698e701b73:/templatetags/nodes.py diff --git a/templatetags/nodes.py b/templatetags/nodes.py index 0cb2289..5ae507d 100644 --- a/templatetags/nodes.py +++ b/templatetags/nodes.py @@ -1,79 +1,114 @@ from django import template from django.conf import settings from django.contrib.sites.models import Site +from django.core.urlresolvers import reverse, NoReverseMatch +from django.template.defaulttags import kwarg_re +from django.utils.encoding import smart_str +from philo.exceptions import ViewCanNotProvideSubpath register = template.Library() class NodeURLNode(template.Node): - def __init__(self, node, with_obj, as_var): - if node is not None: - self.node = template.Variable(node) - else: - self.node = None - - if with_obj is not None: - self.with_obj = template.Variable(with_obj) - else: - self.with_obj = None - + def __init__(self, node, as_var, with_obj=None, view_name=None, args=None, kwargs=None): self.as_var = as_var + self.view_name = view_name + + # Because the following variables have already been compiled as filters if they exist, they don't need to be re-scanned as template variables. + self.node = node + self.with_obj = with_obj + self.args = args + self.kwargs = kwargs def render(self, context): - try: - if self.node: - node = self.node.resolve(context) - else: - node = context['node'] - current_site = Site.objects.get_current() - if node.has_ancestor(current_site.root_node): - url = '/' + node.get_path(root=current_site.root_node) - if self.with_obj: - with_obj = self.with_obj.resolve(context) - subpath = node.view.get_subpath(with_obj) - if subpath[0] is '/': - subpath = subpath[1:] - url += subpath - else: + if self.node: + node = self.node.resolve(context) + else: + node = context.get('node', None) + + if not node: + return settings.TEMPLATE_STRING_IF_INVALID + + if self.with_obj is None and self.view_name is None: + url = node.get_absolute_url() + else: + if not node.view.accepts_subpath: return settings.TEMPLATE_STRING_IF_INVALID - if self.as_var: - context[self.as_var] = url - return settings.TEMPLATE_STRING_IF_INVALID + if self.with_obj is not None: + try: + view_name, args, kwargs = node.view.get_reverse_params(self.with_obj.resolve(context)) + except ViewCanNotProvideSubpath: + return settings.TEMPLATE_STRING_IF_INVALID + else: # self.view_name is not None + view_name = self.view_name + args = [arg.resolve(context) for arg in self.args] + kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) for k, v in self.kwargs.items()]) + + url = '' + try: + subpath = reverse(view_name, urlconf=node.view, args=args, kwargs=kwargs) + except NoReverseMatch: + if self.as_var is None: + if settings.TEMPLATE_DEBUG: + raise + return settings.TEMPLATE_STRING_IF_INVALID else: - return url - except: - return settings.TEMPLATE_STRING_IF_INVALID + url = node.construct_url(subpath) + + if self.as_var: + context[self.as_var] = url + return '' + else: + return url @register.tag(name='node_url') def do_node_url(parser, token): """ - {% node_url [] [with ] [as ] %} + {% node_url [for ] [as ] %} + {% node_url with [for ] [as ] %} + {% node_url [ [ ...] ] [for ] [as ] %} + {% node_url [= [= ...] ] [for ] [as ]%} """ params = token.split_contents() tag = params[0] + as_var = None + with_obj = None + node = None + params = params[1:] - if len(params) <= 6: - node = None - with_obj = None - as_var = None - remaining_tokens = params[1:] - while remaining_tokens: - option_token = remaining_tokens.pop(0) - if option_token == 'with': - try: - with_obj = remaining_tokens.pop(0) - except IndexError: - raise template.TemplateSyntaxError('"%s" template tag option "with" requires an argument specifying an object handled by the view on the node' % tag) - elif option_token == 'as': - try: - as_var = remaining_tokens.pop(0) - except IndexError: - raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag) - else: # node - node = option_token - return NodeURLNode(node=node, with_obj=with_obj, as_var=as_var) - else: - raise template.TemplateSyntaxError('"%s" template tag cannot accept more than five arguments' % tag) \ No newline at end of file + if len(params) >= 2 and params[-2] == 'as': + as_var = params[-1] + params = params[:-2] + + if len(params) >= 2 and params[-2] == 'for': + node = parser.compile_filter(params[-1]) + params = params[:-2] + + if len(params) >= 2 and params[-2] == 'with': + with_obj = parser.compile_filter(params[-1]) + params = params[:-2] + + if with_obj is not None: + if params: + raise template.TemplateSyntaxError('`%s` template tag accepts no arguments or keyword arguments if with is specified.' % tag) + return NodeURLNode(with_obj=with_obj, node=node, as_var=as_var) + + if params: + args = [] + kwargs = {} + view_name = params.pop(0) + for param in params: + match = kwarg_re.match(param) + if not match: + raise TemplateSyntaxError("Malformed arguments to `%s` tag" % tag) + name, value = match.groups() + if name: + kwargs[name] = parser.compile_filter(value) + else: + args.append(parser.compile_filter(value)) + return NodeURLNode(view_name=view_name, args=args, kwargs=kwargs, node=node, as_var=as_var) + + return NodeURLNode(node=node, as_var=as_var) \ No newline at end of file