I am facing this probelm in my e-commerce project when i try to pagination
Cannot resolve keyword '' into field. Choices are: created_at, description, id, is_active, subcategories, thumbnail, title, url_slug
# CATEGORIES
class CategoriesListView(ListView):
model = Categories
template_name = "admin_local/category_list.html"
paginate_by = 3
def get_queryset(self):
filter_val = self.request.GET.get("filter", "")`enter code here`
order_by = self.request.GET.get("orderby", "id")
if filter_val != "":
cat = Categories.objects.filter(
Q(title__contains=filter_val) | Q(description__contains=filter_val)).order_by(order_by)
else:
cat = Categories.objects.all().order_by(order_by)
return cat
def get_context_data(self, **kwargs):
context = super(CategoriesListView, self).get_context_data(**kwargs)
context["filter"] = self.request.GET.get("filter", "")
context["orderby"] = self.request.GET.get("orderby", "")
context["all_table_fields"] = Categories._meta.get_fields()
return context
I am facing this probelm in my e-commerce project when i try to pagination
This Is html file
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link"
href="{% url 'category_list' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }} ">Previous</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link"
href="#">Previous</a>
</li>
{% endif %}
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link"
href="{% url 'category_list' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }} ">Next</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link"
href="#">Previous</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
</div>
The reason you get this is because you use orderby={{ orderby }} which is empty if it is not filled in.
You should pass the context with:
context['orderby'] = self.request.GET.get('orderby', 'id')
furthermore you should |urlencode the parameters:
<a class="page-link" href="{% url 'category_list' %}?filter={{ filter|urlencode }}&orderby={{ orderby|urlencode }}&page={{ page_obj.next_page_number }} ">Next</a>
You might also want to avoid ordering by an arbitrary field, since ordering can expose sensitive information, for example trying to order by the (hashed) password of a user.
Related
class ProductList(ListView):
model = Product
paginate_by = 8
def company_page(request, slug):
...
product_list = Product.objects.filter(company=company).order_by('-pk')
paginator = Paginator(product_list, 4)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'product/product_list.html', {
...,
'product_list': product_list,
'page_obj': page_obj
})
views.py
<nav aria-label="Pagination">
<ul class="pagination justify-content-center my-5">
{% if page_obj.has_previous %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{page_obj.previous_page_number}}" tabindex="-1" aria-disabled="true">
Newer</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
Newer</a>
</li>
{% endif %}
{% if page_obj.has_next %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{page_obj.next_page_number}}">
Older</a>
</li>
{% else %}
<li class="page-item disabled mx-auto lead">
<a class="page-link" href="#!">
Older</a>
</li>
{% endif %}
</ul>
</nav>
product_list.html
I added pagination on ProductList view with paginated_by and imported Paginator to make other pages using a function view but it's only paginated on ProductList view and doesn't work on company_page view. The Newer & Older buttons work but the page keeps showing every product_list objects. How can I make it work on all pages?
Try this:
views.py
# other views ...
def company_page(request, slug):
product_list = Product.objects.filter(company=company).order_by('-pk')
page = request.GET.get('page', 1)
paginator = Paginator(product_list, 4)
try:
Products = paginator.page(page)
except PageNotAnInteger:
Products = paginator.page(1)
except EmptyPage:
Products = paginator.page(paginator.num_pages)
context = {'Products': Products}
return render(request, 'product/product_list.html', context)
product_list.html
<nav aria-label="Pagination">
{% if Products.has_other_pages %}
<ul class="pagination justify-content-center my-5">
{% if Products.has_previous %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ Products.previous_page_number }}" tabindex="-1" aria-disabled="true">
Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
Previous</a>
</li>
{% endif %}
{% for i in Products.paginator.page_range %}
{% if Products.number == i %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ i }}">
{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if Products.has_next %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ Products.next_page_number }}">
Next</a>
</li>
{% else %}
<li class="page-item disabled mx-auto lead">
<a class="page-link" href="#!">
Next</a>
</li>
{% endif %}
</ul>
{% endif %}
</nav>
I’m trying to create a next and previous button on a single(detail) page. I don’t understand how to make this happen. These are my codes
views.py
def playsong(request, id,slug, tag_slug=None):
beat = Number_beat.objects.get(created_beats=id)
album = Album.objects.get(album_id= id)
albu = Album_beats.objects.filter(album_name= id)
bea = Beats.objects.all()
nextbeat = Number_beat.objects.filter(id__gt = beat.id).order_by(‘id’).first() #.values(‘id’)[:1]
lastbeat = Number_beat.objects.filter(id__lt= beat.id).order_by(‘id’).last()
tag = None
if tag_slug:
tag = get_object_or_404(Tag,slug=tag_slug)
beat=beat.filter(tags__in=[tag])
context={
'beat':beat,
'nextbeat':nextbeat,
'lastbeat':lastbeat,
'album':album,
'albu':albu, }
return render(request, 'music/playsong.html', context)
html
{% if lastbeat %}
<li class="page-item">
<a class="page-link" href="{% url 'playsong' lastbeat %}?{{ request.GET.urlencode }}" id="pred">{{ lastbeat }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{% url 'index' %}" id="pred">home</a>
</li>
{% endif %}
{% if nextbeat %}
<li class="page-item">
<a class="page-link" href="{% url 'playsong' %}?next={{ nextbeat|urlencode }}" id="predj">{{nextbeat}}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{% url 'index' %}" id="pred">home</a>
</li>
{% endif %}
please can anyone help on can I do
my goal is to have a 'user_profile' page that displays relevant information of the user of interest.
Furthermore, the 'user_profile' page should include all the posts that were created by the respective user as new blog entries.
These posts, however, should be filterable with the application 'django-filter' and be paginated. At the moment I have difficulties to paginate the filtered posts. So my question is how to achieve the latter?
So far, I used following approach:
filters.py
import django_filters
class AccountPostFilter(django_filters.FilterSet):
title = django_filters.CharFilter(lookup_expr='icontains')
category = django_filters.ChoiceFilter(choices=cat_list)
class Meta:
model = Post
fields = ['title', 'category']
views.py
class UserProfile(DetailView, MultipleObjectMixin):
model = Account
template_name = 'account/user_profile.html'
paginate_by = 5
def get_context_data(self, **kwargs):
posts = Post.objects.all().filter(author=self.kwargs['pk'])
context = super().get_context_data(object_list=posts, **kwargs)
context['filterset'] = AccountPostFilter(self.request.GET, queryset=posts)
return context
Thank you very much for your time. Best wishes,
Daniel
There is another way of doing this, and do it in a clean and professional way, which will save you the trouble of using Django Filters:
Create a helper function called clean_filters (This will help you clean filters that come in from the brownser:
def clean_filters(filters):
filters = {k: v for k, v in filters.items() if v}
return filters
Create another help function called search (this will help you get the parameters from the GET request and put them in a **filters inside the django filter directive. And return them back with the paginator so you can keep the same filters when moving from page to page):
from 'your_utils_file' import clean_filters
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def search(request):
filters = {
"account__first_name__icontains": request.GET.get("fname_kw"), # put your filters here
"account__last_name__icontains": request.GET.get("lname_kw"), # put your filters here
}
html_queries = {
"fname_kw": request.GET.get("fname_kw"),
"lname_kw": request.GET.get("lname_kw"),
}
filters = clean_filters(filters)
html_queries = clean_filters(html_queries)
posts = Post.objects.filter(**filters) # put your model here
page = request.GET.get('page', 1)
paginator = Paginator(posts, 8)
try:
posts= paginator.page(page)
except PageNotAnInteger:
posts= paginator.page(1)
except EmptyPage:
posts= paginator.page(paginator.num_pages)
return posts
Here is your view (this simply calls the search function to reduce the code of your view and make it easy for your code to maintain):
def search_page(request):
posts = search(request)
if posts is not None:
context = {
'posts': posts,
}
return render(request, "core/index.html", context)
return redirect("index")
Here is your HTML (just a classic pagination code for Django and Bootstrap. This also has the filter and the value of the filter in a loop inside the GET request):
<div class="mb-5">
{% if posts.has_other_pages %}
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
{% if posts.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ posts.previous_page_number }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}" tabindex="-1">
<i class="fa fa-angle-left"></i>
<span class="sr-only">Prev</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="javascript:void(0)" tabindex="-1">
<i class="fa fa-angle-left"></i>
<span class="sr-only">Prev</span>
</a>
</li>
{% endif %}
{% for i in posts.paginator.page_range %}
{% if posts.number == i %}
<li class="page-item active"><a class="page-link" href="javascript:void(0)">{{ i }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ posts.next_page_number }}{% for fil, fil_value in filters.items %}&{{fil}}={{fil_value}}{% endfor %}">
<i class="fa fa-angle-right"></i>
<span class="sr-only">Next</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="javascript:void(0)">
<i class="fa fa-angle-right"></i>
<span class="sr-only">Next</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
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 %}
Code:
class MyObjects(LoginRequiredMixin, ListView):
model = AllObjects
template_name = "my_objects.html"
paginate_by = 10
def get_queryset(self, *args, **kwargs):
queryset = super(MyObjects, self).get_queryset()
return queryset.filter(added_by=self.request.user).order_by('-last_modified')
I have a view that lists user's addings to a table. The problem is pagination is not working properly. I think it is because each time django renders the page, it filters the queryset again, causing only first 10 items to be listed. What can be done to handle this problem? Or should i not use generic view for doing such thing?
Template:
<table>
{% for obj in object_list %}
<tr>
<td>
{{ obj.name}}
</td>
</tr>
{% endfor %}
</table>
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item {% if not page_obj.has_previous %}disabled{%endif%}">
<a class="page-link" {% if page_obj.has_previous %} href="?sayfa={{ page_obj.previous_page_number }}" {% endif %} aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% for page in page_obj.paginator.page_range %} {% if page == page_obj.number %}
<li class="page-item active"><a class="page-link" href="#">{{ page }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?sayfa={{ page }}">{{ page }}</a></li>
{% endif %} {% endfor %}
<li class="page-item {% if not page_obj.has_next %}disabled{%endif%}">
<a class="page-link" {% if page_obj.has_next %}href="?sayfa={{ page_obj.next_page_number }}" {% endif %} aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
I found my mistake. In my template, i used the link "?sayfa={{ page }}". ("sayfa" means page in Turkish, so it's localized version) It's a leftover from my previous pagination which i made with function based view. One way to fix is changing all "sayfa"'s to "page" but since this is not great for localization purposes adding page_kwarg = "sayfa" to my view fixed the problem. Thanks for the answers!