jinja: How to get max of two values - flask

in a list pagination, I want to render the current page with two pages before and after it, providing it's not zero or one. I tried:
{% for p in range(max(1, list.cur_page - 2), min(list.cur_page + 2, list.pages)) %}
<li class="page-item"><a class="page-link" href="{{ list.url }}/{{ p }}">{{ p }}</a></li>
But it doesn't recognize min and max, I know that there is a filter named min max but how can I apply it here?

It seems I can use min and max filters in range parameters,
range([list.cur_page - 2, 2] | max, ...)
so I have:
{% if list.pages > 1 %}
<ul class="pagination float-start flex-wrap ms-5">
{{ render_button(list, 1) }}
{% for p in range([list.cur_page - 2, 2] | max, [list.cur_page + 3, list.pages - 1] | min ) %}
{{ render_button(list, p) }}
{% endfor %}
{{ render_button(list, list.pages) }}
</ul>
{% endif %}

Related

Apply if-else statement on a dictionary using django-templates

In a django - webapp I am classifying between two classes of images i.e. Ants and Bees
I have returned the dictionary to the templates(index.html)
context={
'ant':("%.2f" % predictions[0]),
'bee': ("%.2f" % predictions[1]),
}
when applying this
{% for key , value in pred.items %}
<p>{{key}}: {{value}}%</p>
{% endfor %}
i got this which is pretty much what i wanted to display now i want to display the one with greater probability how do i do it ?
I cannot access elements of the dictionary inside if else statement , though i tried doing this
{% for key, value in pred.items %}
{% if value.0 > value.1 %}
<p>Result : {{value.0}}</p>
{% elif value.0 < value.1 %}
<p>Result: {{key}}</p>
{% endif %}
{% endfor %}
Since your data structure does not look very dynamic and flexible, you could do it the following static way:
Result:
{% if pred.ant > pred.bee %}
Ant: {{ pred.ant }}
{% elif pred.ant < pred.bee %}
Bee: {{ pred.bee }}
{% else %}
Ant: {{ pred.ant }}
Bee: {{ pred.bee }}
{% endif %}

how to use objects in django template

I have such object:
data[ 'aaa' ] = ['1', 'something1']
data[ 'bbb' ] = ['2', 'something2']
And want to display it (using loop ) in template :
{% for row in data %}
<span>{{ row }}</span>>
{% for d in data.row %}
{{ d.0 }} || {{ d.1 }}
{% endfor %}
{% endfor %}
But i see only values within the span tag ( even though array is not empty )
Can you tell me what I am doing wrong ?
Thanks in advance,
The way you're trying to iterate over each row doesn't make sense - either you iterate, or you fetch by index, but doing both will not work. Try this instead:
{% for row in data %}
{{ d.0 }} || {{ d.1 }}
{% endfor %}

count number of instances django template

I've read all the other answers posted with some saying you can and some saying you can't so I tried. What I'm trying to do is iterate my array and if the object's id matches, increment the counter and display it later. I have it set up like this:
{% with elect_count=1 %}
{% for device in devices %}
{% if device.ixDeviceType.ixDeviceClass_id == 3 %}
{{ elect_count|add:1 }}//increment the counter
{% endif %}
{% endfor %}
<li style="list-style: none;" class="padding5">
<span class="glyphicon glyphicon-flash" style="color: yellow; font-size: larger;"></span>
<span name="meter-count">{{ elect_count }}</span>//display total number of elect_count
<ul id="meter-summary">
</ul>
</li>
{% endwith %}
but when I run this, it displays 1 1 1 1 instead of incrementing this elect_count variable and when I do {{ elect_count }} it's 0
You cannot save the counter in template, but you could do it in views and pass it in context:
views.py
def view_function(request):
elect_count = 0
for device in devices:
if device.ixDeviceType.ixDeviceClass_id == 3:
elect_count += 1
context['elect_count'] = elect_count

Django pagination - How to limit the pages?

I'm using this code to display the pagination on my page
<ul class="pagination pagination-sm">
{% if restaurants.has_previous %}
<li>Prev</li>
{% endif %}
{% for page in restaurants.paginator.page_range %}
<li class="{% if restaurants.number == page %}active{% endif %}">{{ page }}</li>
{% endfor %}
{% if restaurants.has_next %}
<li>Next</li>
{% endif %}
</ul>
The issue is that the code above shows all page like this:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | and so on..
Instead I would like to show something like this:
1 | 2 | 3 | 4 | 5
How can I do that?
This is my view:
def listing(request):
list_restaurants = ShopAccount.objects.filter(is_active=1)
# only active products
paginator = Paginator(list_restaurants, 20) # Show 20 products per page
page = request.GET.get('page')
try:
restaurants = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
restaurants = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
restaurants = paginator.page(paginator.num_pages)
return render_to_response('restaurants/list.html', {'restaurants': restaurants}, context_instance=RequestContext(request))
I use something like this :
<li {% ifequal page current %}class="active"{% endifequal %}>
<a href={% ifequal page -4 %}
"/blog/1/"><<
{% else %}{% ifequal page -3 %}
"/blog/{{ current | add:"-1" }}/"><
{% else %}{% ifequal page -2 %}
"/blog/{{ current | add:"1" }}/">>
{% else %}{% ifequal page -1 %}
"/blog/{{ maximum }}/">>>
{% else %}{% ifequal page 0 %}
"#">...
{% else %}{% ifequal page current %}
"#" class="page_link">{{ page }}
{% else %}
"/blog/{{ page }}/">{{ page }}
{% endifequal %}
{% endifequal %}
{% endifequal %}
{% endifequal %}
{% endifequal %}
{% endifequal %}
</a>
</li>
and these views :
def makepaginator(current, maximum):
"""makepaginator() returns a set of number which reprensents buttons.
-4 means first page.
-3 means previous page.
-2 means next page.
-1 means last page.
0 means a dot.
others means the number of the target page."""
NB_PAGES_LEFT_LEFT = 3
NB_PAGES_RIGHT_RIGHT = NB_PAGES_LEFT_LEFT
NB_PAGES_CENTER_RIGHT = 3
NB_PAGES_CENTER_LEFT = NB_PAGES_CENTER_RIGHT
i = 2
current = int(current)
if current > 1:
p = [-4, -3]
else:
p = []
p.append(1)
while i <= maximum:
if (i > NB_PAGES_LEFT_LEFT and i < maximum - NB_PAGES_RIGHT_RIGHT
and (i - current > NB_PAGES_CENTER_RIGHT
or current - i > NB_PAGES_CENTER_RIGHT + 1)):
p.append(0)
while (i > NB_PAGES_LEFT_LEFT
and i < maximum - NB_PAGES_RIGHT_RIGHT
and (i - current > NB_PAGES_CENTER_RIGHT
or current - i > NB_PAGES_CENTER_LEFT + 1)):
i += 1
else:
p.append(i)
i += 1
if current < maximum:
p.append(-2)
p.append(-1)
return (p)
def news(request, page_num=1):
paginator = Paginator(Article.objects.all().order_by('-date'), settings.ARTICLES_PER_PAGE)
try :
page = paginator.page(page_num)
print(type(page_num))
return (render(request, "main/blog.html",
{"paginator" : paginator, "page_num" : int(page_num),
"page" : page,
"buttons" : makepaginator(page_num,
paginator.num_pages)}))
except (PageNotAnInteger, EmptyPage) as e:
return (notfound(request))
With bootstrap I get this :
It may look dirty but it works with my website. You can try it.
If you have some improvements to suggests, I would be glad though. :)
ShopAccount.objects.filter(is_active=1)[:5]
Try this code above, or use the [:5] on the paginator.
I solved this issue with JS.
Here the views:
class AllOrders(LoginRequiredMixin, ListView):
model = Order
template_name = 'all_orders.html'
paginate_by = 20
def get_queryset(self):
filter_val = self.request.GET.get("filter", "")
order_by = self.request.GET.get("orderby", "id")
if filter_val != "":
orders = Order.objects.filter(Q(transaction_id__contains=filter_val) | Q(customer_id__auth_user_id__first_name__contains=filter_val) |
Q(customer_id__auth_user_id__last_name__contains=filter_val)).order_by(order_by)
else:
orders = Order.objects.all().order_by(order_by)
return orders
def get_context_data(self, **kwargs):
context = super(AllOrders, self).get_context_data(**kwargs)
context["filter"] = self.request.GET.get("filter", "")
context["orderby"] = self.request.GET.get("orderby", "id")
context["all_table_fields"] = Order._meta.get_fields()
return context
Here the template:
<nav class="d-inline-block">
<ul class="pagination mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="{% url 'custom_user:all_orders' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }}" tabindex="-1"><i class="fas fa-chevron-left"></i></a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1"><i class="fas fa-chevron-left"></i></a>
</li>
{% endif %}
{% for i in paginator.page_range %}
<li class="page-item {% if i == page_obj.number %}active{% endif %}"><a class="page-link" href="{% url 'custom_user:all_orders' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ i }}">{{ i }} <span class="sr-only">(current)</span></a></li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'custom_user:all_orders' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }}"><i class="fas fa-chevron-right"></i></a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#"><i class="fas fa-chevron-right"></i></a>
</li>
{% endif %}
</ul>
</nav>
Here the JS:
<script>
let pages = document.getElementsByClassName('page-item');
let pageActive;
if (pages.length > 5) {
for (let i = 0; i < pages.length; i++) {
if (pages[i].classList.contains('active')){
pageActive = i;
break;
}
}
for (let j = 0; j < pages.length; j++) {
if ( j != 0 && j != 1 && j < (pageActive - 1)) {
pages[j].setAttribute('hidden', true);
} else if (j != (pages.length - 1) && j != (pages.length - 2) && j > (pageActive + 1)) {
pages[j].setAttribute('hidden', true);
}
};
};
</script>
This is the result:
paginator

Get current URL kwargs in the template?

I'm accomplishing this at the moment by doing:
context['card_type'] = self.kwargs['card_type']
context['role_line'] = self.kwargs['role_line']
context['sort_by'] = self.kwargs['sort_by']
Which seems crazy counter intuitive to me.
Say if i was already at the urls of players/one/two/three
Is there an already prebuilt way to get current kwargs of one, two & three for use in templates?
Edit
urls.py
urlpatterns = patterns('',
url(
r'^$',
NationListView.as_view(),
name='index'
),
url(
r'^(?P<slug>[a-z-]*)/$',
NationDetailView.as_view(),
name='nation'
),
url(
r'^(?P<slug>[a-z-]*)/(?P<card_type>[a-z]*)/(?P<role_line>[a-z]*)/(?P<sort_by>[a-z0-9]*)/$',
NationDetailFilteredView.as_view(),
name='nation_filter'
),
)
The mixin that builds the context
class CoreDetailFilteredMixin(object):
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(CoreDetailFilteredMixin, self).get_context_data(**kwargs)
base_objects(context)
# Pull all the players that belong to the object_type
context['players'] = Player.objects.filter(
**{filters: context['object'].asset_id}
)
# Define the available card types
card_types = {
'if': {'card_type__gte': 2},
'gold': {'overall_rating__gte': 75},
'silver': {'overall_rating__range': (65, 74)},
'bronze': {'overall_rating__lte': 64}
}
# Check if the given card type is in the dictionary because 'all' throws an KeyError
if self.kwargs['card_type'] in card_types:
context['players'] = context['players'].filter(**card_types[self.kwargs['card_type']])
# Don't show inform cards for specific colour card types
if self.kwargs['card_type'] not in ['if', 'all']:
context['players'] = context['players'].exclude(card_type__gte=2)
# Define available role lines
role_lines = {
'att': 3,
'mid': 2,
'def': 1,
'gk': 0
}
# Check if the given role line is in the dictionary because 'all' throws an KeyError
if self.kwargs['role_line'] in role_lines:
context['players'] = context['players'].filter(role_line=role_lines[self.kwargs['role_line']])
# Define the available sort by keys
sorts = {
'ovr': 'overall_rating',
'att1': 'card_att1',
'att2': 'card_att2',
'att3': 'card_att3',
'att4': 'card_att4',
'att5': 'card_att5',
'att6': 'card_att6r'
}
# Add a descending order to the existing queryset
context['players'] = context['players'].order_by('-' + sorts[self.kwargs['sort_by']])
# Create pagination
cbv_pagination(self, context, context['players'], 28, 'players')
context['card_type'] = self.kwargs['card_type']
context['role_line'] = self.kwargs['role_line']
context['sort_by'] = self.kwargs['sort_by']
return context
How i use it currently in the template
{% with object.get_class_name|add:'s'|add:':'|add:object.get_class_name|add:'_filter'|lower as url_string %}
<dl class="sub-nav">
<dt>Card Type:</dt>
{% with 'all if gold silver bronze' as card_types %}
{% for ct in card_types.split %}
{% cycle 'All' 'Inform' 'Gold' 'Silver' 'Bronze' as card_type_name silent %}
{% if card_type == ct %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug ct role_line|default:'all' sort_by|default:'ovr' %}">
{{ card_type_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
<dl class="sub-nav">
<dt>Role Line:</dt>
{% with 'all att mid def gk' as role_lines %}
{% for rl in role_lines.split %}
{% cycle 'All' 'Attackers' 'Midfielders' 'Defenders' 'Goalkeepers' as role_lines_name silent %}
{% if role_line == rl %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug card_type|default:'all' rl sort_by|default:'ovr' %}">
{{ role_lines_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
<dl class="sub-nav">
<dt>Sort By:</dt>
{% with 'ovr att1 att2 att3 att4 att5 att6' as sorts %}
{% for sort in sorts.split %}
{% ifequal role_line 'gk' %}
{% cycle 'Overall' 'Diving' 'Handling' 'Kicking' 'Reflexes' 'Speed' 'Positioning' as sorts_name silent %}
{% else %}
{% cycle 'Overall' 'Pace' 'Shooting' 'Passing' 'Dribbling' 'Defending' 'Heading' as sorts_name silent %}
{% endifequal %}
{% if sort_by == sort %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug card_type|default:'all' role_line|default:'all' sort %}">
{{ sorts_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
{% endwith %}
As I learnt here, the view is already passed to the context (for class-based views). So you can do the following in the template without needing to explicitly pass the kwargs from the view:
{{ view.kwargs.card_type }}
{{ view.kwargs.role_line }}
{{ view.kwargs.sort_by }}
You can use dict.update():
update([other])
Update the dictionary with the key/value pairs from other, overwriting existing keys.
context.update(self.kwargs)