In a template, how do I get what page I'm currently on? I'd rather not pass a variable like page , especially when I know some request.xxx can provide me with the information.
<li {% if page=="home" %}class="active"{% endif %}>
Home
</li>
<li {% if page=="about" %}class="active"{% endif %}>
About
</li>
As long as you've imported request, request.path should contain this information.
Using request.path doesn't seem to be a proper approach since you'll have to update the paths in case of changing URL rules or deploying your site under a subfolder.
Use request.url_rule.endpoint instead, it contains actual endpoint name independent of actual path:
(Pdb) request.url_rule.endpoint
'myblueprint.client_pipeline'
In a template:
<li {% if request.url_rule.endpoint == "myblueprint.client_pipeline" %}class="active"{% endif %}>Home</li>
Good luck!
First import request from flask in your application. Then you can use it without passing to template:
<li {%- if request.path == "/home" %} class="active"{% endif %}>
Home
</li>
<li {%- if request.path=="/about" %} class="active"{% endif %}>
About
</li>
To avoid using hard-coded URLs you can use the url_for function like this:
{% for ni in ['index', 'foo', 'bar', 'baz'] %}
<li {%- if request.path == url_for(ni) %} class="active"{% endif %}>{{ ni | capitalize }}</li>
{% endfor %}
In this case index, foo, bar and baz would be function names, used like this in your python code:
#app.route('/')
def index():
Try
<li {% if request.endpoint == "blueprintname.routename" %}class="active"{% endif %}>Home</li>
This one worked for me.
You can also use .split if your url has more stuff in it.
Example:
/product
/product/add
/product/32432/edit
/product/32432/view
{{ request.path.split('/')[1] }}
This will return only "product"
Related
The title says everything. Two days ago the following code worked fine but now journeys is not set or empty or ...
def map(request, jid):
journeys = None
if request.user.is_authenticated:
journeys = Journey.objects.filter(user_id=request.user.id)
#some stuff
context = {
'jc': len(journeys), #only for testing
'journeys': journeys
}
return render(request, 'JourneyMap/map.html', context)
map.html extends base.html
Inside base.html:
<div class="dropdown-menu" aria-labelledby="dropdown05">
<p>{{ jc }}</p> <-- only for testing
{% for journey in journeys %}
{% if journey.user_id == user.user_id %}
{% if forloop.counter < 4 %}
<a class="dropdown-item"
href="{% url 'JourneyMap_journey' jid=journey.id %}">{{ journey.title }}</a>
{% endif %}
{% endif %}
{% endfor %}
</div>
Result:
It seems like journeys length is 1, so the variable is actually set.
I think that your user check fails here.
{% if journey.user_id == user.user_id %}
What is user.user_id here? Is user another variable that lives somewhere outside of the given context? Then probably it's not set.
Otherwise, if you want to check for current user's id, perhaps you should do:
{% if journey.user_id == request.user.id %}
I'm trying to allow for dynamic template tags. Specifically, I have a menu setup that I'm defining in code vs templates. And I would like to render the menu label as {{ request.user }}. So how can I define that as a string in Python, and allow the template to parse and render the string as intended. And not just variables too, templatetags as well ({% provider_login_url 'google' next=next %}).
What am I missing?
Update with code:
I'm specifically designing my menus with django-navutils, but that's less important (basically the package just stores the defined data and then uses templates to render it).
from navutils import menu
top_horizontal_nav = menu.Menu('top_nav')
left_vertical_nav = menu.Menu('left_nav')
menu.register(top_horizontal_nav)
menu.register(left_vertical_nav)
sign_in = menu.AnonymousNode(
id='sign_in',
label='Sign In',
url='{% provider_login_url "google" next=next %}',
template='nav_menu/signin_node.html',
)
user = menu.AuthenticatedNode(
id='user_menu',
label='{{ request.user }}',
url='#',
template='nav_menu/username_node.html'
)
top_horizontal_nav.register(sign_in)
top_horizontal_nav.register(user)
What I would like to do, is now render these string values ('{{ request.user }}') in my templates
{% load navutils_tags %}
<li
class="{% block node_class %}nav-item menu-item{% if node.css_class %} {{ node.css_class }}{% endif %}{% if is_current %} {{ menu_config.CURRENT_MENU_ITEM_CLASS }}{% endif %}{% if has_current %} {{ menu_config.CURRENT_MENU_ITEM_PARENT_CLASS }}{% endif %}{% if viewable_children %} has-children has-dropdown{% endif %}{% endblock %}"
{% for attr, value in node.attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
<a href="{{ node.get_url }}" class="nav-link"{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>{% block node_label %}{{ node.label }}{% endblock %}</a>
{% if viewable_children %}
<ul class="{% block submenu_class %}sub-menu dropdown{% endblock %}">
{% for children_node in viewable_children %}
{% render_node node=children_node current_depth=current_depth|add:'1' %}
{% endfor %}
</ul>
{% endif %}
</li>
So, for the above, where I'm rendering {{ node.label }}, how can I get the value stored in node.label to actually be parsed as a request.user? This similarly applies for the URL of value {% provider_login_url "google" next=next %}.
You can create a custom template tag and render those. Like this
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def render_nested(context, template_text):
# create template from text
tpl = template.Template(template_text)
return tpl.render(context)
Then in template
...
<a href="{{ node.get_url }}" class="nav-link"
{% for attr, value in node.link_attrs.items %} {{ attr }}="{{ value }}"{% endfor %}>
{% block node_label %}{% render_nested node.label %}{% endblock %}
</a>
...
Haven't tested but I think it will work.
More on template: https://docs.djangoproject.com/en/dev/ref/templates/api/#rendering-a-context
More on custom tags: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-tags
If I understand you well, you want to write template code that renders to template code and then be processed again. Something like ... meta-templates?
I can see you already figured out the first part, but now you need the resulting code to be parsed again in order to set the respective value for {{ request.user }}.
I achieve that by using middleware, but since parsing a template is an expensive operation I implemented some a mechanism to apply the "re-parsing" process just to urls/views of my selection.
The model.
class ReparsingTarget(models.Model):
url_name = models.CharField(max_length=255)
Simple enough, just a model for storing those URL names I want to be affected by the middleware.
The middleware.
class ReparsingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# We are no interested in whatever happens before
# self.get_response is called.
response = self.get_response(request)
# Now we will re-parse response just if the requested url
# is marked as target for re-parse.
if self._marked(request) and isinstance(response, TemplateResponse):
# Decode the template response code ...
content = response.content.decode('utf-8')
# Create a Template object ...
template = Template(content)
# Provide request to de context ...
context_data = response.context_data
context_data.update({'request': request})
# ... and renders the template back the the response.
response.content = template.render(Context(response.context_data))
return response
def _marked(self, request):
url_name = resolve(request.path_info).url_name
return ReparsingTarget.objects.filter(url_name=url_name).exists()
It is a really simple implementation, the tricky part for me was to figure out how to put the idea into Django code.
In practice.
Some model.
class Foo(models.Model):
label = models.CharField(max_length=255)
The template:
{% for foo in foos %}
{% comment %} Remember foo.label == '{{ request.user }}' {% endcomment %}
<p> Username: {{ foo.label }} </p>
{% endfor %}
The stored Foo instance:
And the result:
I've been trying to do this and getting no results
<ul>
{% for topic in topics %}
<li {% if request.get_full_path == "/topic/{{ topic.topic_slug }}/" %}class="is-active"{% endif %}>
{{ topic.topic_name }}
</li>
{% endfor %}
</ul>
The error, I'm guessing is from the {{ topic.topic_slug }} being rendered in the string. I'd like it to be "/topic/tech/" during rendering but that seems not to be working.
I don't believe you can use {{ }} inside a {% %} so you need to do this in a different way. There are many possibilities.
Try using
{% if request.get_full_path == "/topic/"+topic.topic_slug+"/" %}
but the way I would do it is to simply use your class to do the work of returning the path. /topic/tech/ looks like what people usually return from a get_absolute_url class function:
class Topic:
...
def get_absolute_url(self):
return '/topic/{}/'.format(self.topic_slug)
and then in your template, simply use:
{% if request.get_full_path == topic.get_absolute_url %}
(Note that if you already have an absolute_url, simply use another function name. e.g. get_my_topic_slug_url()).
I did use django pagination, but there is a problem with urls, here is my urls.py:
url(r'^/blog/$', blog_view.main, name='blog'),
url(r'^/blog/page/(?P<page_id>\d{0,9})$', blog.post, name='blog_page'),
My views.py:
def post(request, page_id=None):
posts = Posts.objects.all()
pageid = page_id
return render(request, 'base.html', {'posts': posts, 'pageid': pageid,})
My base.html which use bootstrap:
{% url 'blog_page' as blog_page %} # Blog page need follow patterns
<ul>
{% for post in posts %}
<li {% if request.path == htt://myblog.com/blog/page/5 %} class="active" {% endif %}>{{ post.title }}</li> # When I put blog_page django shows error. Help me how to put something to fix this condition.
{% endfor %}
</ul>
As stated in the documenation on HttpRequest objects,
HttpRequest.path is
A string representing the full path to the requested page, not including the scheme or domain.
Example: "/music/bands/the_beatles/"
(emphasis mine).
So, in your test, leave out the scheme (which you, btw, incorrectly wrote as htt://) and domain parts:
<li {% if request.path == /blog/page/5 %} class="active" {% endif %}>{{ post.title }}</li>
I am trying change the active selection of my navigation links based on the current page where the user is at.
I am trying to do omething like this:
<li {% if request.get_full_path == {% url profile_edit_personal %} %}class="current"{% endif %}>Personal Details</li>
Alternatively, I know I could define do something like this:
<li class="{% block current %}{% endblock %}">Personal Details</li>
and add a {% block current %}current{% endblock %} to each of the relevant templates but I would prefer something like what Im trying to achieve in the first example if possible
Thanks!
Since you'll probably only need to do this once--in your nav template--it makes more sense to me to keep everything in one place.
First reverse your url names and store them in variables like Timmy suggested, then simply compare them in the template:
{% url 'about_page' as about %}
...
<ul id="nav">
<li class="{% ifequal request.path about %}active{% endifequal %}">About</li>
...
Just make sure you have your request context processor enabled so you have access to the request in the template. Do this by adding django.core.context_processors.debug in your TEMPLATE_CONTEXT_PROCESSORS settings variable.
This is quite a common requirement so it might be worthwhile writing your own template tag to perform this:
class isCurrentNode(template.Node):
def __init__(self, patterns):
self.patterns = patterns
def render(self, context):
path = context['request'].path
for pattern in self.patterns:
curr_pattern = template.Variable(pattern).resolve(context)
if path == curr_pattern:
return "current"
return ""
#register.tag
def is_current(parser, token):
""" Check if the browse is currently at this supplied url"""
args = token.split_contents()
if len(args) < 2:
raise template.TemplateSyntaxError, "%r tag requires at least one argument" % args[0]
return isCurrentNode(args[1:])
and in your template
{% url about_page as about %}
{% url home_page as home %}
...
<ul>
<li class="{% is_current home %}">Home</li>
<li class="{% is_current about %}">About</li>
...
Here's the same idea done slightly differently:
http://gnuvince.wordpress.com/2007/09/14/a-django-template-tag-for-the-current-active-page/
http://www.turnkeylinux.org/blog/django-navbar
How about:
<li {% if request.get_full_path == profile_edit_personal.get_absolute_url %}
class="current"{% endif %}><a href="{% url profile_edit_personal %}">
Personal Details</a></li>
where get_absolute_url is as discussed in the Django docs.
Its still probably not the best way to customise active nav menu headers though, there's probably some CSS tricks that can do it without as much code. I'd say more but only had half a cup of coffee this morning..