Django template : How to simulate break function or while loop [duplicate] - python

I have a product list that put 3 products on a row and clears the row and adds another 3, this works fine everywhere but IE6, i know that adding <div> around each group of 3 products will solve this is the template file at the moment
{% for product in category.products.all %}
<div class="{% cycle 'clear' '' '' %}">
<img src="{{MEDIA_URL}}{{product.mini_thumbnail}}" alt="{{product.name}}" class="thumbnail"/>
<div class="prod-details">
<h3>{{product.get_product_name}}</h3>
<h4 class="strap">{{product.get_product_detail}}</h4>
<p>{{ product.strap }}</p>
<ul>
<li class="price">£{{product.price}}</li>
<li class="quantity">
<select name="quantity_{{product.id}}">
<option label="1" value="1">1</option>
<option label="2" value="2">2</option>
<option label="3" value="3">3</option>
<option label="4" value="4">4</option>
<option label="5" value="5">5</option>
<option label="6" value="6">6</option>
<option label="7" value="7">7</option>
<option label="8" value="8">8</option>
<option label="9" value="9">9</option>
</select>
</li>
<li>Details ></li>
<li class="right"><input type="submit" name="add_to_basket_{{product.id}}" value="Add to Basket >"/></li>
</ul>
</div>
</div>
{% endfor %}

codeape's solution only works if you are using a very recent SVN checkout of Django trunk. If you're using version 1.1 or below, that syntax is not supported.
Instead, you can use the divisibleby filter:
{% if forloop.counter|divisibleby:3 %}<div>{% endif %}

Use forloop.counter and a modulo operator inside the loop:
{% for ... %}
{% if forloop.counter|divisibleby:3 %}<div>{% endif %}
...
{% if forloop.counter|divisibleby:3 %}</div>{% endif %}
{% endfor %}
See http://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
EDIT:
Fixed the code example.

Related

User selected number of objects per page in Django

I made pagination for my site but I want to let the user choose how many records are displayed at one time e.g. 10, 15, 25. This is my views.py
def finished_ads_view(request):
queryset = Campaign.objects.filter(completion_percent=100)
try:
per_page = request.GET['dropdown']
except:
per_page = 1
page = request.GET.get('page', 1)
paginator = Paginator(queryset, per_page)
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
context = {
'posts': posts,
}
return render(request, 'finished_campaigns.html', context)
And this is part of my template:
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if posts.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1" aria-label="Previous">
<span aria-hidden="true">«</span>
<span class="sr-only">begin</span>
</a>
</li>
{% endif %}
{% for n in posts.paginator.page_range %}
{% if posts.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
</li>
{% elif n > posts.number|add:'-3' and n < posts.number|add:'3' %}
<li class="page-item"><a class="page-link" href="?page={{ n }}">{{ n }}</a></li>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ posts.paginator.num_pages }}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %}
</ul>
</nav>
<select name="dropdown">
<option value="1">1</option>
<option value="2">2</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
<input type="submit" value="Submit"/>
</form>
The problem is that the dropdown value does not change and the number of records displayed at one time is still the same as the except: per_page value.
You should wrap your select and submit in a form so the value gets passed to the backend in query string.
<form method="get">
<input type="hidden" name="page" value="{{ page }}">
...
</form>
Also pagination parameter needs to be included so I added that. You need to add it to the context as well. Then when creating links for the pages with GET attribute don't forget to pass the dropdown as well.
To see the whole template can be better. I can only imagine:
<form>
<-- any staff here -->
<input type="hidden" name="page" value="{{ request.GET.page }}">
<-- any staff here -->
<select name="dropdown">
<option {% if request.GET.dropdown == "1" %}selected{% endif %}
value="1">1</option>
<option {% if request.GET.dropdown == "2" %}selected{% endif %}
value="2">2</option>
<option {% if request.GET.dropdown == "15" %}selected{% endif %} value="15">15</option>
<option {% if request.GET.dropdown == "20" %}selected{% endif %} value="20">20</option>
</select>
<-- any staff here -->
<input type="submit" />
<-- any staff here -->
</form>
Dont forget to add request in context, if you don't have request context processor.

How to use pagination after you query for results?

I'm trying to make a search functionality with 2 parameters. Everything works fine, until I want to use pagination.
I've been testing it by displaying only 1 element per page. This works, until I want to change the page.
When I change the page, I get no results even though I have entries that should be displayed in the DB.
Tbh I think that I should somehow store the search parameters and do the query when the page changes, but that makes no sense for me. How does pagination help if I still have to do the query everytime I change the page?
Views.py
def cautare(req):
intrari_oferte = Oferta.objects.get_queryset().distinct('denumireMeserie')
context = {
'title': "Cautare loc de munca | Best DAVNIC73",
'oferte': intrari_oferte
}
return render(req, "../templates/pagini/cautare-loc-de-munca.html", context)
def locuridemunca(req):
jud = req.POST.get('inputjudet')
meserie = req.POST.get('inputmeserie')
intrari_oferte = Oferta.objects.filter(judet=jud, denumireMeserie=meserie)
pagIntrari = Paginator(intrari_oferte, 1)
page = req.GET.get('page')
pagina = pagIntrari.get_page(page)
context = {
'title': "Cautare loc de munca | Best DAVNIC73",
'judet': jud,
'meserie': meserie,
'pagina': pagina
}
return render(req, "../templates/pagini/locuri-de-munca.html", context)
cautare template
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-centru">
<h1 class="heading-contact">Cauta loc de munca</h1>
<form class="form-contact" action="{% url 'locuridemunca' %}" method="POST">
{% csrf_token %}
<select name="inputjudet" class="selectare-judet-cautare" style="display: block;">
<option selected disabled>Selecteaza judetul!</option>
<optgroup label="Sud Muntenia">
<option value="Prahova">Prahova</option>
<option value="Dambovita">Dambovita</option>
<option value="Calarasi">Calarasi</option>
<option value="Arges">Arges</option>
<option value="Teleorman">Teleorman</option>
<option value="Giurgiu">Giurgiu</option>
<option value="Ialomita">Ialomita</option>
</optgroup>
<optgroup label="Centru">
<option value="Sibiu">Sibiu</option>
<option value="Alba">Alba</option>
<option value="Mures">Calarasi</option>
<option value="Covasna">Covasna</option>
<option value="Harghita">Harghita</option>
<option value="Brasov">Brasov</option>
</optgroup>
</select>
<select name="inputmeserie" class="selectare-meserie-cautare" style="display: block;">
<option selected disabled>Selecteaza meseria!</option>
{% for meserie in oferte %}
<option value="{{ meserie.denumireMeserie }}">{{ meserie.denumireMeserie }}</option>
{% endfor %}
</select>
<div class="form-group form-group-custom">
<input type="submit" value="Cauta!" class="btn btn-secondary btn-selectare-judet-cautare">
</div>
</form>
</div>
{% endblock %}
locuri de munca template
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-munca">
{% if pagina %}
<h1 class="heading-munca">Locuri de munca de {{meserie}} din judetul {{judet}}</h1>
<div class="row">
{% for oferta in pagina %}
<div class="col-md-4">
<div class="card card-custom">
<div class="card-body">
<h5 class="card-title">{{oferta.denumireMeserie}}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{oferta.agentEconomic}}</h6>
<p class="card-text">{{oferta.adresa}}</p>
Card link
</div>
</div>
</div>
{% endfor %}
</div>
{% if pagina.has_other_pages %}
<div class="row">
<div class="col-md-12">
<ul class="pagination">
{% if pagina.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
<li class="page-item active">
<a class="page-link">1</a>
</li>
{% if pagina.has_next %}
<li class="page-item">
»
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">»</a>
</li>
{% endif %}
</ul>
</div>
</div>
{% endif %}
{% else %}
<div class="row">
<div class="col-md-12">
<div class="card card-custom">
<div class="card-body">
<h5 class="card-title" style="text-align: center;">Nu am putut gasi rezultate!</h5>
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}
cautare = search, locuri de munca = jobs.
Basically I want to make a small app that lets someone search for an existing job from the DB, in a specific county. (judet = county)
So how can I make pagination work? Right now when I change the page I get no results.

django if condition not working when using variable, but when using number it's working

why this code not working, i get variable "data" from views.py
when i change data.numrooms with number like '1', it's working well, but is use data.numrooms that's not working
<select class="form-control" name="numadults">
<option value=''>No. of Adult</option>
{% for i in range %}
{% if data.numadults == i %}
<option value="{{ i }}" selected>{{ i }}</option>
{% else %}
<option value="{{ i }}">{{ i }}</option>
{% endif %}
{% endfor %}
</select>
Why not put that logic in the view and pass it to template like this:
# view
adult_range = list(map(lambda x: (x, True) if x == data.numadults else (x, False), range(1,10))
# Template
<option value=''>No. of Adult</option>
{% for i, selected in adult_range %}
{% if selected %}
<option value="{{ i }}" selected>{{ i }}</option>
{% else %}
<option value="{{ i }}">{{ i }}</option>
{% endif %}
{% endfor %}
Similarly to ruddra's solution, the easiest way to achieve this is probably to do the bulk of the logic in the view:
adults = [(element, element.number == data.numadults) for element in adult_list]
This will give you a list of two-tuples of (<adult object>, <boolean>) where the boolean represents the conditional you're trying to use in the template to decide whether to use selected attribute.
In the template, you can then base your conditional solely on that boolean:
<option value=''>No. of Adult</option>
{% for i, selected in adult_range %}
{% if selected %}
<option value="{{ i }}" selected>{{ i }}</option>
{% else %}
<option value="{{ i }}">{{ i }}</option>
{% endif %}
{% endfor %}
Note though that you can also evaluate the condition inline, in the html tag, like so:
<option value="{{ i }}" {% if selected %} selected {% endif %}>
This might make for more readable code.

In Django, what's the right way to pre-select a form option tag?

I'm using Django and Python 3.7. I want to create a SELECT menu on my template so I tried this ...
<select id="website_id" name="website_id">
<option value="">Select a website</option>
{% for website in websites %}
<option value="{{ website.id }}" {{ 'selected' if website_id == website.id else '' }}>{{ website.path }}</option>
{% endfor %}
</select>
but I get this error
Could not parse the remainder: ' if website_id == website.id else ''' from ''selected' if website_id == website.id else '''
Its choking on my "if" expression. What's the preferred way to set the "selected" attribute of an option tag?
The real right way is to use a Django form. But if you insist on doing it manually, you need an if tag
{% if website_id == website.id %} selected {% endif %}
The correct syntax is like so:
{% if CONDITION %}A{% endif %}
So in your case, we would implement it like so:
<select id="website_id" name="website_id">
<option value="">Select a website</option>
{% for website in websites %}
<option value="{{ website.id }}" {% if website_id == website.id %}selected{% endif %}>{{ website.path }}</option>
{% endfor %}
</select>
<select name="qf">
<option value="10th" {% if '10th' %} selected {% endif %}>10th</option>
<option value="12th" {% if '12th' %} selected {% endif %}>12th</option>
</select>

django template syntax to iterate through two lists

I have the following django template, where as I'm iterating through a list (class_list_overall), I want to use forloop.counter0 as an index in another list (classTimeSlots). It just keeps giving me a TemplateSyntaxError. I have tried the following variations:
{{classTimeSlots.{{forloop.counter0}}}}
{{classTimeSlots.[forloop.counter0]}}
{{classTimeSlots.{forloop.counter0}}}
{{classTimeSlots.(forloop.counter0)}}
{{classTimeSlots.forloop.counter0}}
{% with forloop.counter0 as index%}
<legend>{{ classTimeSlots.index}}</legend>
{% endwith %}
None of which worked. Any suggestions? I'm just a newbie at DJango. I'm using Google App Engine.
Here's the code snippet (I know it's inefficient but I've been trying different things):
{% for class_list in class_list_overall %}
<fieldset> <legend>{{ classTimeSlots.forloop.counter0 }}</legend>
<ul>
<li> <label>First Choice </label>
<select class="dropdown" name="class{{forloop.counter}}1" size="1">
<option value="Click Here to Choose" selected="selected">Click Here to Choose</option>
{% for class in class_list %}
<option>{{class}}</option>
{% endfor %}
</select>
</li>
<li>
<label>Second Choice </label>
<select class="dropdown" name="class{{forloop.counter}}2" size="1">
<option value="Click Here to Choose" selected="selected">Click Here to Choose</option>
{% for class in class_list %}
<option>{{class}}</option>
{% endfor %}
</select>
</li>
</ul>
</fieldset>
{% endfor %}
Short answer: you can't do that.
The template language will not try to determine the value of a variable passed in dot syntax.
It will do a literal lookup of forloop.counter0
1: write a template tag that accepts a variable and a key, and have it return the variable[key]
2: this can most likely be done in the view. Can I see it?
Django doesn't support this - it's deliberately limited. Instead, you should modify your view function to zip the two lists together, and pass that in to the template.
Its possible but not recommendable:
{% for class_list in class_list_overall %}
<fieldset> <legend>
{% for cts in classTimeSlots %}
{% ifequal forloop.counter forloop.parentloop.counter %} {{cts}}
{% endifequal %}
{% endfor %} </legend>
<ul>
<li> <label>First Choice </label>
<select class="dropdown" name="class{{forloop.counter}}1" size="1">
<option value="Click Here to Choose" selected="selected">Click Here to Choose</option>
{% for class in class_list %}
<option>{{class}}</option>
{% endfor %}
</select>
</li>
<li>
<label>Second Choice </label>
<select class="dropdown" name="class{{forloop.counter}}2" size="1">
<option value="Click Here to Choose" selected="selected">Click Here to Choose</option>
{% for class in class_list %}
<option>{{class}}</option>
{% endfor %}
</select>
</li>
</ul>
</fieldset>{% endfor %}
But its better to take list into parent dict:
[class_list_overall[i].update({'label':classTimeSlots[i]}) for i in range(0,len(classTimeSlots))]
And then change above code to:
<legend>
{{ class_list.label }}
</legend>

Categories