How to recognize the first loop call in if statement? - django

I have code in template:
{% for p in products %}
{% if p.parent == None %}
<li class="{% if forloop.first %}active{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}
In my case class "active" shows me in li with parent != None. I can't use [...]filter(parent=None) in view as I must have a complete list of products.
The problem is that if first object.parent in products =! None Django will think that the first iteration happened so that I will never add active to my class.
So I want to check when the first iteration with successful if statement happened. Any ways to do this?

You could recover the first element in the view in python, add it to the context and then test in your template :
{% for p in products %}
{% if not p.parent %}
<li class="{% if p == first_element %}active{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}

{% with is_first=True %}
{% for p in products %}
{% if p.parent == None %}
<li class="{% if is_first %}active{% endwith % }{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}
Can not test now - but perhaps that work!

You can put this on the objects themselves or as extra variable, when you build the context. Do code like this:
e.g. instead of:
ctx['products'] = Product.objects.all()
do something like this:
ctx['products'] = list(Product.objects.all())
is_first = True
for p in ctx['products']:
p.is_active = p.parent is None and is_first:
is_first = False
Then in the template, just do:
<li class="{% if p.is_active %}active{% endif %}">
{{ p.name|upper }}
</li>
If you don't want to write on the object, use extra variable
ctx['products'] = list(Product.objects.all())
is_first = True
for p in ctx['products']:
if p.parent is None and is_first:
ctx['active_id'] = p.id
break
Then in the template, just do:
<li class="{% if p.id == active_id %}active{% endif %}">
{{ p.name|upper }}
</li>

You can also use forloop.counter like this
{% for p in products %}
{% if forloop.counter == 0 %}
<li class="{% if is_first %}active{% endwith % }{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}

Related

How to use django paginator page range for displaying the first 10 numbers not all?

I want to change the blow script to show just the first 10 page numbers. Now it shows all page numbers. Could you please tell me how to change it? I tried several ways but it didn't work. Any help will be appreciated!
{% if forloop.counter|divisibleby:"3" or forloop.last %}
</div>
{% endif %}
{% endfor %}
{% if is_paginated %}
<div class="row">
<ul class="pagination pagination-md ">
{% if page_obj.has_previous %}
<li>«</li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }}</span></li>
{% else %}
<li><a href="?page={{ i }}{% if currentCategory %}&category={{ currentCategory }}
{% endif %}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
</div>
{% endif %}
</div>

django template tag missing 1 required positional argument : value

In my django project I have custom template tag to set correct next link in pagination :
#register.tag(name='url_replace')
def url_replace(request, field, value):
print('this is form tag',request,field,value)
d = request.GET.copy()
d[field] = value
return d.urlencode()
In my template :
{% if is_paginated %}
<ul class="pagination pull-right">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
Looks every thing fine but it is showing me error
Exception Value:
url_replace() missing 1 required positional argument: 'value'
I am unable to figure out the problem as I passed all three arguments !
Change the #register.tag to #register.simple_tag. #register.tag is something bit more complicated
compare
https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/#django.template.Library.simple_tag
with
https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/#registering-the-tag

Flask: request.view_args always returns an empty dicitonary [duplicate]

This question already has answers here:
Get the data received in a Flask request
(23 answers)
How do you access the query string in Flask routes?
(13 answers)
Closed 4 years ago.
I am trying to paginate my products catalog using paginate() function that comes with Flask .
Inside catalog i am using a search filter to sort products depends on the filter itself, in the url i have more than 5 to 10 arguments, these arguments are always changing and i want the paginate path to contain them .
Inside template i am doing this:
{% if pagination.has_next or pagination.has_prev %}
{{
macros.pagination_widget(
pagination,
request.endpoint,
args=request.view_args
)
}}
{% endif %}
The issue is, request.view_args always returns an empty dictionary , in fact the arguments are in url .
If i tried to hardcode all the arguments by using just some logic like {% if %} and {% else %} which i don't want to, the pagination works just fine .
I solved the problem, by using request.query_string and creating a macro helper everything now is working just fine.
Here is the solution:
_macros_pagination.html
{% macro pagination_widget(pagination, endpoint, extra='') %}
<ul class="uk-pagination uk-flex-center" uk-margin="">
<li{% if not pagination.has_prev %} class="disabled"{% endif %}>
<a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.prev_num, **kwargs) }}&{{extra}}{% else %}#{% endif %}">
<span uk-pagination-previous=""></span>
</a>
</li>
{% for p in pagination.iter_pages() %}
{% if p %}
{% if p == pagination.page %}
<li class="uk-active">
{{ p }}
</li>
{% else %}
<li>
{{ p }}
</li>
{% endif %}
{% else %}
<li class="uk-disabled"><span>...</span></li>
{% endif %}
{% endfor %}
<li{% if not pagination.has_next %} class="disabled"{% endif %}>
<a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.next_num, **kwargs) }}&{{extra}}{% else %}#{% endif %}">
<span uk-pagination-next=""></span>
</a>
</li>
</ul>
{% endmacro %}
template.html
{% import "_macros_pagination.html" as macros %}
{% if pagination.has_next or pagination.has_prev %}
{{
macros.pagination_widget(
pagination,
request.endpoint,
extra=request.query_string
)
}}
{% endif %}

how to make flask pagination keep the query condition

here is my view function:
def get_user_info():
form = UserInfoForm()
query = UserInfo.query
if form.validate_on_submit():
query = query.filter_by(sex=form.sex.data)
flag = False
page = request.args.get('page', 1, type=int)
pagination = query.paginate(page=page, per_page=10, error_out=False)
return render_template("user_info.html", form=form,data=pagination.items, pagination=pagination)
and here is part of my html:
<form class="form-inline" action="{{url_for('.get_user_info')}}", method="post">
{{ form.csrf_token }}
<div class="panel-body">
<div class="form-group">
{{ form.sex.label }}:
{{ form.sex(class="form-control") }}
</div>
<div class="form-group">
{{ form.submit(class="btn btn-primary") }}
</div>
</div>
and here is my pagination macro:
{% macro pagination_widget(pagination, endpoint) %}
{% if pagination.total != 0 %}
<ul class="pagination">
<li{% if pagination.page == 1 %} class="disabled"{% endif %}>
<a href="{% if pagination.page != 1 %}{{ url_for(endpoint, page=1, **kwargs) }}
{% else %}#{% endif %}">««</a>
</li>
<li{% if not pagination.has_prev %} class="disabled"{% endif %}>
<a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.page - 1, **kwargs) }}
{% else %}#{% endif %}">«</a>
</li>
{% for p in pagination.iter_pages() %}
{% if p %}
<li {% if p == pagination.page %} class="active"{% endif %}>
{{ p }}
</li>
{% endif %}
{% endfor %}
<li{% if not pagination.has_next %} class="disabled"{% endif %}>
<a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}
{% else %}#{% endif %}">»</a>
</li>
<li{% if pagination.page == pagination.pages %} class="disabled"{% endif %}>
<a href="{% if pagination.page != pagination.pages %}{{ url_for(endpoint, page=pagination.pages, **kwargs) }}
{% else %}#{% endif %}">»»</a>
</li>
</ul>
{% endif %}
{% endmacro %}
I use a selectfiled sex in my page, when I select male in my page, I get the paginate object and my first page user is all male.But when I click next page, the results will have both male and female, I just want it like the first page, it has only male user info. Thanks.
I have resolved my problem today.
There are *args, and **kwargs for any macro, so I can pass parameters of query condition to it and in my view functions use request.args.get() to obtain parameters and set it to form.

How do I implement a recursive and extensible Twig template?

I'm implementing a simple website menu, but this time I'm using Twig as my template language. The depth of the menu tree is one or greater. Here's my Twig code so far (sanitized and simplified):
{# file menu1.html.twig #}
<ul>
{% import _self as renderer %}
{% for item in menu.items %}
{{ renderer.renderItem(item) }}
{% endfor %}
</ul>
{% macro renderItem(item) %}
{% block itemtag %}
<li>
{% endblock %}
{{ item.name }}
{% if item.hasItems() %}
<ul>
{% import _self as renderer %}
{% for subitem in item.items %}
{{ renderer.renderItem(subitem) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}
Now I need to override the "itemtag" element in another template:
{# file menu2.html.twig #}
{% extends "menu1.html.twig" %}
{% block itemtag %}
<li data-foo="bar">
{% endblock %}
This will not work, as explained very well here: https://stackoverflow.com/a/26650103/220817
So how do I write a Twig template that can traverse and render a tree structure, and still allow extending templates to override certain elements in the rendered markup?
You need to use macro's if you want to do something recursive as macro's can self import themself. Here is an example of a recursive macro:
{% macro menu(m, class, currentLevel, maxLevel) %}
{%if not class is defined %}
{% set class = '' %}
{% endif %}
{%if not currentLevel is defined or currentLevel is null %}
{% set currentLevel = 1 %}
{% endif %}
{%if m is iterable%}
{% set links = m %}
{% else %}
{% set links = m.getLinks() %}
{% if m.showRoot() and m.hasRoot() %}
<li class="root{%if class != ''%} {{class}}{%endif%}">
<a href="{%if m.getRoot().getTreeLeft() > 1 %}{{ m.getRoot().getRoute() }}{% else %}#site_url#{% endif %}" {% if m.getRoot().PageId in selected_page_ids %} class="selected"{% endif %}>{{ m.getRoot().name }}</a>
</li>
{% endif %}
{% if maxLevel is null %}{% set maxLevel = m.getLevel() %}{% endif %}
{% endif %}
{% if not links is empty %}
{% for link in links %}
{% if link['selected'] is defined and link['selected'] %}
{% set is_selected = true %}
{% else %}
{% set is_selected = false %}
{% endif %}
{% set anchor_class = '' %}
{% if link.PageId in selected_page_ids or is_selected %}
{% set anchor_class='selected' %}
{% endif %}
{% if method_exists(link, 'getPageCssClass') and link.getPageCssClass() != null %}
{% set class= class~' '~link.getPageCssClass().getTitle() %}
{% endif %}
<li{%if (class|trim) != '' %} class="{{ (class|trim) }}"{% endif %}>
<a href="{{ link.getRoute }}"{%if (anchor_class|trim) != '' %} class="{{ (anchor_class|trim) }}" {% endif %} {% if link.PageId > 0 %}data-page-id="{{ link.PageId }}"{% endif %}>{{ link.name }}</a>
{% if link.hasPublicChildren and currentLevel < maxLevel %}
<ul>
{{ _self.menu(link.getPublicChildren, 'sec', (currentLevel+1), maxLevel) }}
</ul>
{% endif %}
</li>
{% endfor %}
{% endif %}
{% endmacro %}