简体   繁体   中英

Django tag for relative urls

I want to write a custom url templatetag, that would also work with relative paths (and not only named patterns) and accepts list in arguments (which are later used to call a different view function - that's why I need the request object). This is my tag in template :

{% with '/views' (normally it's a var created in for loop) as link %}
    <a href="{% url_for link params=('website','homepage') %}">Click</a>
{% endwith %}

and tag's code itself :

@register.simple_tag(takes_context = True)
def url_for(context, parser, token):
    request = context['request']
    bits = token.split_contents()
    if len(bits) < 2:
        raise TemplateSyntaxError("'%s' takes at least one argument"
                                  " (path to a view)" % bits[0])
    try:
        if "/" in bits[1]:
            bits[1] = unicodedata.normalize('NFKD', bits[1]).encode('utf-8', 'ignore')
            try:
                bits[1] = resolve(bits[1].replace("'","")).url_name
            except Exception as e:
                log.error('Exception when resolving url for tag: %s' % e)

        viewname = bits[1]
    except Exception as exc:
        raise

    args = []
    kwargs = {}
    asvar = None
    bits = bits[2:]

    if len(bits):
        for bit in bits:
            if 'params' in bit:
                par = ast.literal_eval(bit.split('=')[1])
                my_function(request, par[0], par[1])
                break

    from django.core.urlresolvers import reverse, NoReverseMatch

    url = ''
    try:
        url = reverse(viewname, args=args, kwargs=kwargs, current_app=context.current_app)
    except NoReverseMatch:
        exc_info = sys.exc_info()
        if settings.SETTINGS_MODULE:
            project_name = settings.SETTINGS_MODULE.split('.')[0]
            try:
                url = reverse(project_name + '.' + view_name,
                          args=args, kwargs=kwargs,
                          current_app=context.current_app)
            except NoReverseMatch:
                    six.reraise(*exc_info)
        else:
            raise

    return url

Unfortunately right now the only thing I was able to achieve is TemplateSyntaxError at /: Could not parse the remainder: '('website','homepage')' from '('website','homepage')' . Before that I was trying to monkeypatch the original url tag and URLNode but I had a bunch of different problems there. Any help with tackling this appreciated.

Template files are not Python. Thus, you can't do the tuple thing with your arguments. Instead, refactor the template tag to take this type of syntax:

{% url_for link params='website homepage' %}

Then you have to account for that when parsing the bits variable in the template tag. It ultimately comes down to parsing strings.

The docs:

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-the-compilation-function

See the notes for "token.contents" and "token.split_contents()".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM