Code

Opened 2 years ago

Closed 2 years ago

Last modified 12 months ago

#18584 closed Uncategorized (wontfix)

Ability to fetch urlname from template context

Reported by: foxwhisper 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.

Attachments (0)

Change History (6)

comment:1 Changed 2 years ago by lukeplant

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to wontfix
  • Status changed from new to closed

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 Changed 15 months ago by dickymoe@…

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 Changed 12 months ago by clime

Ye, this should be context processor included by default.

comment:4 Changed 12 months ago by foxwhisper

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. I've emailed Luke and asked him to clarify.

Last edited 12 months ago by foxwhisper (previous) (diff)

comment:5 Changed 12 months ago by lukeplant

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 Changed 12 months ago by foxwhisper

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.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.