Opened 12 years ago

Closed 12 years ago

Last modified 11 years ago

#18584 closed Uncategorized (wontfix)

Ability to fetch urlname from template context

Reported by: Cal Leeming Owned by: nobody
Component: Template system Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Currently to detect what the current urlname is in a template requires adding some code into each view. This is so you can detect what page you are currently on, to place for example CSS classes onto a link to indicate you are on that page.

Really, Django should have the urlname in the request context as standard. I'm currently using the following approach:

context_processors.py:
def resolve_urlname(request):
    """Allows us to see what the matched urlname for this
    request is within the template"""
    from django.core.urlresolvers import resolve
    try:
        res = resolve(request.path)

        if res:
            return {'urlname' : res.url_name}
    except:
        return {}
URL CONF:
url(r'^$', "sites.vf.views.home", name = "home"),

This then allows me to do things like this:

<a title="Home" href="{% url home %}" class="{% if urlname == "home"%}sel{% endif %}">

Essentially, it allows you to keep all aspects of managing a sites URLs within the same code set and forces the same naming convention.

Could a core developer please confirm if such a patch would be accepted into the core? I feel there's a strong case for this.

Change History (6)

comment:1 by Luke Plant, 12 years ago

Resolution: wontfix
Status: newclosed

I don't see any need for this to be in core, it can be added easily as context processor. (In fact it can only be added using a context processor, since Templates can be used without a request object being current, and we are currently avoiding putting the request into any threadlocals).

Although it may be common for you do use this technique, I've never actually had this requirement myself, so I don't think you can argue it is so common that it should be on by default.

comment:2 by dickymoe@…, 11 years ago

It strange that django won't support this kind of feature. A lot a people need to know if they are in the active page to highlight menu or other things.

comment:3 by clime, 11 years ago

Ye, this should be context processor included by default.

comment:4 by Cal Leeming, 11 years ago

Seems as though this was actually added in 1.5

request.resolver_match.url_name
https://docs.djangoproject.com/en/1.5/ref/request-response/#django.http.HttpRequest.resolver_match

Not entirely too sure why Luke said this is not common practice, as he did not offer up any suitable alternative, and it now appears to be in the core.

Version 0, edited 11 years ago by Cal Leeming (next)

comment:5 by Luke Plant, 11 years ago

I'm slightly confused by these questions!

1.5 didn't add this feature, as far as I can see (although it has added something that would help with it). If it did, then I'm not sure what is being asked for - you have your pony!

I did suggest a workaround, which is using a context processor. I'm not convinced that it should be on by default.

The thing is, you don't need to know the name of the current view to be able to work out if a link should be highlighted. Since the link is linking to a URL, not a view function, the easiest is to compare URLs, not compare view functions. So this code works:

    {% url 'my_view' 'arg1' as my_view_url %}
    <a href="{{ my_view_url }}" {% if request.path_info == my_view_url %}class="active"{% endif %}>Some link</a>


With the new HttpRequest.resolver_match attribute, you can also do something similar in a template by matching view names, and without the context processor that would have been needed before, and slightly less boilerplate. Untested:

    <a href="{% url 'my_view' 'arg1' %}" class="{% if request.resolver_match.url_name == "my_view" %}sel{% endif %}">Some link</a>

However, it doesn't work if you've got two different links that use the same view but with different arguments (unless that is what you want). This is one reason that it is better to use the URL, not the view name.

The problem with both these is that there is a lot of repeated code for every link that you want to do it for - the "if x == y then class=active" has to be repeated every time.

Since this scales badly, neither of these are solutions I'd want to promote. Instead, since this need almost always comes up in the context of menus and navigation, I would do the necessary preprocessing in some view code, where you can do a loop over all the menu items and decorate them appropriately, producing a list of menu items, and then have a loop similarly in your template to produce the HTML. Or, as is common with many CMS apps, in a template tag that does all of this for you for your menu.

I might occasionally do it as above, but it is quick-and-dirty solution that doesn't scale.

comment:6 by Cal Leeming, 11 years ago

Thanks for clarifying this Luke.

I see what you mean now about comparing the URL rather than the view name, and I completely agree that both of these feel messy due to the bulk of repeated code. I also agree that implementing your own menu system in the view is usually the best way forward, it's much more flexible and cleaner. However this is a slightly steep learning curve for new users of Django, so hopefully this ticket will serve as some guidance for others in the future.

Note: See TracTickets for help on using tickets.
Back to Top