How to pass variable into Django block in url? - django

Context
I am trying to loop through a list of objects, then call on the name and id attribute and pass it into the Url block as regex to be captured in the urls.py later.
Problem
{%if people_found%}
{%for the_people in people_found%}
{{the_people.firstname}}
{%endfor%}
{%endif%}
Urls.py
app_name = 'Search4Bday'
urlpatterns= [path("search/profile/<str:firstname>/<int:id>", views.profile, name = "profile")]
Question
I'm not sure how I can pass the variables into the urls.py file if I can't call on the variable the_people with double curly braces. I'm also not sure if this is the correct way to pass in the variables into the regular expression capture portion of the urls.py. Any ideas?

Use add tag of Django Template Lang:
{% if people_found %}
{% for the_people in people_found %}
{{the_people.firstname}}
{% endfor %}
{% endif %}
edit: I didn't pay attention to urls.py and this will not work as wanted. Instead of adding slashes between variables put them directly. So this should work.
{% if people_found %}
{% for the_people in people_found %}
{{the_people.firstname}}
{% endfor %}
{% endif %}

I tried another method, I could have just done this:
{% if people_found %}
{% for the_people in people_found %}
{{the_people.firstname}}
{% endfor %}
{% endif %}
https://docs.djangoproject.com/en/4.0/ref/templates/language/

Related

How to apply multiple if condition filter in djago template

I am rendering two filter from my views to html template. 1) notifications_approved 2)notifications_pending. I am using this two filter separately in my html. Is there any way to use this two filter together in if statement? here is my code:
#html template
{% for notification in notifications_approved %}
{% endif %}
{% for notification in notifications_pending %}
{%endif%}
I tried this but it's not rendering anything's in my template:
{%if notification in notifications_approved or notifications_pending %}
{%endif%}
I also tried this
{%if notification|notifications_approved or notification|notifications_pending %}
{%endif%} #getting TemplateSyntaxError
I also surprised very much why this if statement not working:
{% if notification in notifications_approved %}
{% endif %}
views.py
def ShowAuthorNOtifications(request):
notifications_approved = Notifications.objects.filter(notification_type="Comment Approved").order_by('-date')
notifications_pending = Notifications.objects.filter(notification_type="New Comment").order_by('-date')
{% if notification in notifications_approved %}
{% endif %}
If statement not working because we are not comparing anything. notifications_approved is a query set which contains list of objects. You need to loop it first. Secondly, if you need to check if the query set is empty or not, use:
{% with notifications_approved as np %}
{% if np %}
# your code
{% endif %}
{% endwith %}
OR
{% if notifications_approved or notifications_pending %}
OR
{% if notifications_approved.exists or notifications_pending.exists %}
OR
{% if notifications_approved.all or notifications_pending.all %}
You can use empty tag as well to check if empty:
{% for na in notifications_approved %}
# code
{% empty %}
# code for empty query set
{% endfor %}

How simplify calling include with multiple viariables in Django template?

I want to simplify (make more readable) Django template code:
{% comment %}
required variables:
group_id = 'exclude-brands-group'
select_name = 'exclude-brands'
entities = 'excludeBrandsSets'
add_keyword_name = {% trans 'Brand' %}
url_edit_keywords = {{ url_project_filter_exclude_brands_edit_keywords }}
{% endcomment %}
{% with group_id='exclude-keywords-group' select_name='exclude-keywords' %}
{% with entities=excludeKeywordsSets %}
{% trans 'Words' as add_keyword_name %}
{% with url_edit_keywords=url_project_filter_exclude_keywords %}
{% include 'web_site/seo/frontend/seo/filtered_keyword_idea/template/keyword_filter_group.html' %}
{% endwith %}
{% endwith %}
{% endwith %}
But I do not have idea how to reduce number of with tags - since include is only one line command. I have not idea how simplify trans. Do you know some simpler way to pass variables to templates?
The include tag lets you pass additional context to the template. That means you don't need separate with tags (although the downside is you end up with very long lines). There isn't any way to include the trans tag.
{% trans 'Words' as add_keyword_name %}
{% include 'web_site/seo/frontend/seo/filtered_keyword_idea/template/keyword_filter_group.html' with group_id='exclude-keywords-group' select_name='exclude-keywords' entities=excludeKeywordsSets url_edit_keywords=url_project_filter_exclude_keywords %}

URL output in template is empty

URL pattern declaration from views.py
url(r'^intentions/(\d+)/$', 'intentions.views.show'),
When I am writing address directly, like intentions/1 works ok, but when I trying to display URL show for object like:
{% for i in intentions %}
{% url 'intentions.views.show' i.id as iUrl %}
<li>{{ i }}</li>
{% endfor %}
I am ending with empty href. Could someone give me any advice?
If you are using Django 1.3 or 1.4, make sure you are loading the new url tag. Add the following line to the top of your template:
{% load url from future %}
If you are using Django 1.4 or earlier, and you haven't loaded the new url tag as above, then you need to remove the single quotes from the url pattern:
{% url intentions.views.show i.id as iUrl %}
As an aside, it's recommended to name your url pattern:
url(r'^intentions/(\d+)/$', 'intentions.views.show', name='show_intention'),
Then change your template to:
{% for i in intentions %}
{% url 'show_intention' i.id as iUrl %}
<li>{{ i }}</li>
{% endfor %}
you could try
{% for i in intentions %}
<li><{{ i }}</li>
{% endfor %}
don't use {% url 'intentions.views.show' i.id as iUrl %}, it's maybe confused.
Also,you could try modifiy the url as follow
url(r'^intentions/(\d+)/$', 'intentions.views.show', name="intention_view"),
then,
{% for i in intentions %}
{% url "intention_view" i.id as iUrl %}
<li>{{ i }}</li>
{% endfor %}
If there are also ending empty href,try the first method.
'intentions.views.show'
Also give a name='' to your URL and use it in your template code.

Use django-pagination to generate link refl=next/prev

I'm using django-pagination to paginate my pages. It works great, but I would like to set up
<link rel="prev" href="http://www.example.com/foo/?page=1" />
<link rel="next" href="http://www.example.com/foo/?page=3" />
to the <head>, like it is recommended by google .
However I found no way ho to do this (without extra queries at least). First I tried to edit the pagination/templates/pagination.html with something like this
{% block extra_head %}
<link rel=... ... />
{% endblock %}
Which of course did not work (pagination.html is included by the {% paginate %} tag, it does not extend my layout.html). Next, I tried to modify my template for /foo/ view to something like this (adding the {% block extra_head %}):
{# foo.html #}
{% extends "layout.html" %}
{% block content %}
{% load pagination_tags %}
{% autopaginate object_list %}
{% paginate %}
{% for obj in object_list %}
{{ obj }}
{% endfor %}
{% paginate %}
{% endblock %}
{% block extra_head %}
<link rel="prev" href="?page={{ page_obj.previous_page_number }}"/>
{% endblock %}
But this won't work either, as the page_obj variable is only available in scope of {% block content %}. A could call
{% autopaginate object_list %}
in the extra_head block, but that will mean an extra hit to the db (and possibly other side effects that I'm not aware of). Is there an elegant way to solve this, ideally as DRY as possible?
Edit: I'm using django 1.2.
You can do {% autopaginate %} in higher-level block, then paginated objects will be available in sub-blocks. If you don't have higher level block it is possible to do this in base template:
{% block root %}
...
{% endblock %}
And in extended template:
{% extends "base.html" %}
{% load pagination_tags %}
{% block root %}
{% autopaginate objects 10 %}
{{ block.super }}
{% endblock %}
<!-- the rest of your code -->
Now, to get a different rendering of paginator in head, you can make use of the with tag:
{% with we_are_in_head=1 %}
{% paginate %}
{% endwith %}
And override templates/pagination/pagination.html with something like this:
{% if we_are_in_head %}
# Your links to next and prev only
{% else %}
# original code
{% endif %}
A moral
This is not elegant and the reason is that pagination should be implemented in the view. Templates are for rendering only, template-tags too. Pagination makes extra sql queries, it also parses arguments from request, template is totally wrong place for this code, so workarounds has to be invented. These workarounds might break on next release of django, they are also subtle and can be accidentally broken by other developer.
We can call autopaginate in a view and then use {% paginate %} as usual. Here is a recipe if somebody still face the described problem:
from pagination.templatetags.pagination_tags import AutoPaginateNode
def autopaginate(request, context, queryset_var, paginate_by):
""" It allows us to use paginated objects in different template blocks """
autopagination = AutoPaginateNode(queryset_var, paginate_by)
# Inject a request - it's required by `autopagination` function
context['request'] = request
autopagination.render(context)

Interpolate Django template include variable

I'm doing something like
{% for part in parts %}
{% include "inc.html" with o=part prefix="part{{ forloop.counter0 }}_" %}
{% endfor %}
where inc.html could be something of such kind:
<p id="{{ prefix }}para">{{ o.text }}</p>
I just discovered the prefix variable isn't interpolated and "part{{ forloop.counter0 }}_" is passed literally.
Any relatively elegant work-around?
I think the best solution would be to register an inclusion_tag, that would handle the part and forloop.counter operations:
#register.inclusion_tag("inc.html")
def inc_tag(part, loop_counter):
prefix = 'part%s_' % (loop_counter,)
context = {
'part': part,
'prefix': prefix,
}
return context
And you would call it like that
{% for part in parts %}
{% inc_tag part=part loop_counter=forloop.counter0 %}
{% endfor %}
Your way is also doable like so, but I wouldn't recommend that
{% for part in parts %}
{% with "part"|add:forloop.counter0|add:"_" as prefx %}
{% include "inc.html" with o=part prefix=prefix %}
{% endwith %}
{% endfor %}