User selected number of objects per page in Django - python

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.

Related

filter to pagination django

implemented sorting and pagination on the product page, but sorting gets confused when moving to the next page. How do I apply a filter to all pagination pages?and i got smth weird with dropdown selection: after moving to next pages it starts act like crazy,after choosing a filter and refreshing the page, it returns to the default value and seems to be changing places (exmp: $$-$ -> $-$$ and vice versa , and i must guess who is who :) )
template
<div class="product-sorting d-flex">
<p>Sort by:</p>
<form name="selectForm" action="{% url 'shop' %}" method="get">
<label for="orderby"></label>
<select name="orderby" id="orderby" onchange="selectForm.submit();">
<option value="price">price: $$ - $</option>
<option value="-price">price: $ - $$</option>
</select>
<input type="submit" class="d-none" value="submit">
</form>
</div>
views
class Shop(ListView):
template_name = 'essense/shop.html'
context_object_name = 'items'
paginate_by = 9
allow_empty = False
model = Item
def get_context_data(self, *, object_list=None, **kwargs):
***context***
def get_ordering(self):
return self.request.GET.get('orderby', )
pagination
{% if page_obj.has_other_pages %}
</div>
<nav aria-label="navigation">
<ul class="pagination mt-50 mb-70">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link"
href="?page={{ page_obj.previous_page_number }}"><i
class="fa fa-angle-left"></i></a>
</li>
{% endif %}
{% for p in page_obj.paginator.page_range %}
{% if page_obj.number == p %}
<li class="page-item"><a class="page-link" href="#">{{ p }}</a></li>
{% elif p > page_obj.number|add:-3 and p < page_obj.number|add:+3 %}
<li class="page-item"><a class="page-link" href="?page={{ p }}">{{ p }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link"
href="?page={{ page_obj.next_page_number }}"><i
class="fa fa-angle-right"></i></a></li>
{% endif %}
</ul>
</nav>
</div>
</div>
{% endif %}
You are only passing the new page number with the pagination link, so any other parameters that may have been involved in filtering will get lost on the new page.
You need a way to maintain the extra GET params. One way to do this might be a template tag that you can pass the new page number to;
project/templatetags/pagination_tags.py:
from django import template
register = template.Library()
#register.simple_tag
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
Then in your template the next (and previous) links would use that tag:
{% load pagination_tags %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?{% url_replace request 'page' page_obj.next_page_number %}">
<i class="fa fa-angle-right"></i>
</a>
</li>
{% endif %}

TypeError at /products/ object of type 'ModelBase' has no len()

So I'm trying to use pagination, When I visit the page I get TypeError at /products/
object of type 'ModelBase' has no len(). The traceback shows this line has the error
books = haha.page(page)
views.py
def showproducts(request):
oof = CartItem.objects.filter(user=request.user).values_list('book', flat=True)
lmao = OrderItem.objects.filter(user=request.user).values_list('book', flat=True)
hehe = CartItem.objects.filter(user=request.user)
category = Category.objects.all()
haha = Paginator(Book, 2)
page = request.GET.get('page')
if page is None:
page = 1
fianlprice = 0
for item in hehe:
fianlprice += item.book.price
# books = Book.objects.all()
books = haha.page(page)
return render(request, 'main/products.html', {'books':books, 'price':fianlprice, 'cart':oof, 'order':lmao, 'category':category})
products.html
<h1>Products</h1>
<h1>{{ error }}</h1>
{% if user.is_authenticated %}
<h1>Your cart currently costs ${{ price }}</h1>
{% else %}
<h1>Please login to view your cart</h1>
{% endif %}
<form method="GET" action="/search/">
<label>Choose a category</label>
<select name="category" id="category">
<option value="All" selected>All</option>
{% for name in category %}
<option value="{{ name.name }}">{{ name.name }}</option>
{% endfor %}
</select>
<input type="text" placeholder="Search here" name="search" id="search">
<button type="submit">Search</button>
</form>
{% for book in books %}
<h3>{{ book.name }}</h3>
<img src= "/media/{{ book.image }}" alt="">
<p>{{ book.description }}</p>
{% if not user.is_authenticated %}
<p>Please login</p>
{% else %}
{% if book.id in cart %}
<form method="POST" action="/removefromcartforhome/">
{% csrf_token %}
<button type="submit" name="removeid" value="{{ book.id }}">remove item from cart</button>
</form>
{% elif book.id in order %}
<h3>You already own this</h3>
{% else %}
<form method="POST" action="/addtocartforhome/">
{% csrf_token %}
<button type="submit" name="bookid" value="{{ book.id }}">Add to cart</button>
</form>
{% endif %}
{% endif %}
{% endfor %}
{% if books.has_other_pages %}
{% if listing.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
{% for i in books.paginator.page_range %}
{% if books.number == i %}
<li class="page-item active">
<a class="page-link">{{i}}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
{% if books.has_next %}
<li class="page-item">
»
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">»</a>
</li>
{% endif %}
{% else %}
{% endif %}
The paginator needs a QuerySet, not a model, so:
# queryset &downarrow;
haha = Paginator(Book.objects.all(), 2)

How to pass a value to a search query

I am working with two pages and I would like to click on a tag on one page, which would insert a value to a search query on another page.
So here's my views.py:
def bikes_all(request):
item_list = Bike.objects.all()
category_q = request.GET.get('cat')
if category_q:
item_list = item_list.filter(category__pk=category_q)
paginator = Paginator(item_list, 10)
page = request.GET.get('page')
try:
items = paginator.page(page)
except PageNotAnInteger:
items = paginator.page(1)
except EmptyPage:
items = paginator.page(paginator.num_pages)
context = {
'items': items,
}
return render(request, "bikes_all.html", context)
and my template:
<form method="GET" action="{% url 'core:bikes_all' %}">
<div class="form-row ">
<div class="form-group col-5">
<label for="category">Category</label>
<select id="cat" class="form-control" name="cat">
<option value="" {% if not request.GET.cat %} selected {% endif %}>Choose...</option>
{% for cat in category_list %}
<option value="{{ cat.pk }}" {% if request.GET.cat == cat.pk|slugify %} selected {% endif %}>
{{ cat }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-row">
<button type="submit" class="btn btn-outline-primary btn-md">Search</button>
</div>
</form>
and here's the a tag from another page:
<div class="col-md-4 overlay zoom">
<a href="{% url 'core:bikes_all' %}">
<div style="position:relative;">
<img src="{% static '/img/category_choice/bike33.png' %}" class="img-fluid">
<div class="card-img-overlay">
<h2 class="card-title"
style="text-align: center; color: aliceblue; position: absolute; bottom:5px;">
Road Bikes
</h2>
</div>
</div>
</a>
</div>
So I have {% url 'core:bikes_all' %} in my href, which takes to bikes_all.html , but I would like to pass a search query within that href as well. I was trying to do {% url 'core:bikes_all' request.GET.cat=2 %} or {% url 'core:bikes_all' category_q=2 %}, but it didnt work.
The search query looks like that, when I filter the results by category http://localhost:8000/bikes/all?cat=1
So my aim is to redirect user to http://localhost:8000/bikes/all?cat=2 , when he clicks on that a tag on first page.
You are getting GET parameters in your request so you need to pass that GET parameter in your url like this:
https://url?parameter=2
so set the cat=i in your bikes_all url:
{% url 'core:bikes_all' %}?cat=i

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 template : How to simulate break function or while loop [duplicate]

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.

Categories