Pagination Based on Queryset - django

I'm trying to implement pagination on my Django app that is based on the filtered queries, but the pagination shows all the objects even the ones not filtered, any insight on what I'm doing wrong?
Any assistance would be appreciated.
def searchPropertyListView(request):
city = City.objects.all().annotate(
num_property=Count("property")).order_by("-num_property")
categories = Category.objects.all()
purposes = Purpose.objects.all()
featured = list(Property.objects.filter(featured=True))
shuffle(featured)
querySet = Property.objects.all()
city_or_neighborhood = request.GET.get('city_or_neighborhood')
category = request.GET.get('category')
purpose = request.GET.get('purpose')
if city_or_neighborhood != '' and city_or_neighborhood is not None:
querySet = querySet.filter(Q(city__title__icontains=city_or_neighborhood)
| Q(neighborhood__title__icontains=city_or_neighborhood)
).distinct()
if category != '' and category is not None:
querySet = querySet.filter(category__title=category)
if purpose != '' and purpose is not None:
querySet = querySet.filter(purpose__title=purpose)
paginator = Paginator(querySet, 1)
page = request.GET.get('page')
try:
querySet = paginator.page(page)
except PageNotAnInteger:
querySet = paginator.page(1)
except EmptyPage:
querySet = paginator.page(paginator.num_pages)

Paginator.get_page is New since Django 2.0.
def searchPropertyListView(request):
...
Your code here
...
paginator = Paginator(querySet, 1)
page = request.GET.get('page')
page_obj = paginator.get_page(page)
And html
{% for property in page_obj %}
{{ property.city.title }}<br>
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
See Using Paginator in a view function

Related

Filtering and pagination in Django 2x

It looks like the django-filter-mixin still has issues with Django 2x. So I'm trying to do it the 'old fashioned way'. The following starts with the filter criteria which works without fault, The pagination code is included but it is not working, I can't figure out if it's an issue with the view or the template (both included)
views.py
def allcontainer(request):
allcontainer = Container.objects.all()
container_list = Container.objects.all()
user_list = User.objects.all()
type = request.GET.get('type')
name = request.GET.get('name')
rack = request.GET.get('rack')
shelf = request.GET.get('shelf')
if (
type =='' or type is None and
name =='' or name is None and
rack =='' or rack is None and
shelf =='' or shelf is None
):
allcontainer = allcontainer
if type !='' and type is not None:
allcontainer = allcontainer.filter(container_type__iexact=type)
if name !='' and name is not None:
allcontainer = allcontainer.filter(container_name__iexact=name)
if rack !='' and rack is not None:
allcontainer = allcontainer.filter(location_id__location_name__iexact=rack)
if shelf !='' and shelf is not None:
allcontainer = allcontainer.filter(location_id__location_sub_name__iexact=shelf)
qs = allcontainer
paginator = Paginator(qs, 25)
page = request.GET.get('page')
try:
pub = paginator.page(page)
except PageNotAnInteger:
pub = paginator.page(1)
except EmptyPage:
pub = paginator.page(paginator.num_pages)
# url_filter = PublicationFilter(request.GET, queryset=qs)
context = {
'container':allcontainer,
'type': type,
'pub':pub,
# 'url_filter':url_filter
# name
# rack
# shelf
}
return render(request, 'container/allcontainer.html', context)
template
...
{% if pub.has_other_pages %}
<p>a</p>
{% if pub.has_previous %}
<p>b</p>
previous
<!-- </li> -->
{% else %}
<li class="disabled"><span>???</span></li>
{% endif %}
{% for i in pub.paginator.page_range %}
{% if pub.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if pub.has_next %}
<li>next</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
{% endif %}
</section>
...
In your code replace
pub = paginator.page(page)
with
pub = paginator.get_page(page)

Pagination in Wagtail

I'm fairly new to Wagtail, and I am in the process of creating a site that will have a Resources (blog) section and I'm not sure how to implement pagination so that there are only 5 posts on each page and the user has to click a number (1, 2, 3, etc.) to go to the next page to see the next 5 posts.
I have this in my template for the pagination section of the resource/blog index page:
<ul class="pagination">
<li><i class="fa fa-angle-left"></i></li>
<li class="active">1</li>
<li>2</li>
<li>3</li>
<li><i class="fa fa-angle-right"></i></li>
</ul>
What code do I need to incorporate to make this functional? Thanks in advance.
Django provides the module django.core.paginator for this purpose: https://docs.djangoproject.com/en/1.10/topics/pagination/ . Using this within Wagtail is very similar to the examples in the Django documentation - the only real difference is that when you're setting up the Paginator object to be passed to the template, you do that with a get_context method on the page model, instead of a view function. Your model definition will look something like this:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
class ResourceIndexPage(Page):
# ...
def get_context(self, request):
context = super(ResourceIndexPage, self).get_context(request)
# Get the full unpaginated listing of resource pages as a queryset -
# replace this with your own query as appropriate
all_resources = ResourcePage.objects.live()
paginator = Paginator(all_resources, 5) # Show 5 resources per page
page = request.GET.get('page')
try:
resources = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
resources = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
resources = paginator.page(paginator.num_pages)
# make the variable 'resources' available on the template
context['resources'] = resources
return context
Within your template, you can now loop over the items using {% for resource in resources %}, and display the pagination links as follows:
<ul class="pagination">
{% if resources.has_previous %}
<li><i class="fa fa-angle-left"></i></li>
{% endif %}
{% for page_num in resources.paginator.page_range %}
<li {% if page_num == resources.number %}class="active"{% endif %}>{{ page_num }}</li>
{% endfor %}
{% if resources.has_next %}
<li><i class="fa fa-angle-right"></i></li>
{% endif %}
</ul>
I very much appreciate that you got me here - thanks so much for the assist. I had to make some adjustments to make it work. Here's the model if anyone comes across the same issue:
class NewsIndexPage(Page):
intro = RichTextField(blank=True)
def get_context(self, request):
context = super(NewsIndexPage, self).get_context(request)
# Get the full unpaginated listing of resource pages as a queryset -
# replace this with your own query as appropriate
blogpages = self.get_children().live().order_by('-first_published_at')
paginator = Paginator(blogpages, 3) # Show 3 resources per page
page = request.GET.get('page')
try:
blogpages = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
blogpages = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
blogpages = paginator.page(paginator.num_pages)
# make the variable 'resources' available on the template
context['blogpages'] = blogpages
return context
...and here's the HTML:
<ul class="pagination">
{% if blogpages.has_previous %}
<li>
<i class="fa fa-angle-left"></i>
</li>
{% endif %}
{% for page_num in blogpages.paginator.page_range %}
<li {% if page_num == blogpages.number %} class="active"{% endif %}>
{{ page_num }}
</li>
{% endfor %}
{% if resources.has_next %}
<li>
<i class="fa fa-angle-right"></i>
</li>
{% endif %}
</ul>
It works like a charm - and adds to the learning curve!
In case it's useful to anyone, I wanted this to work as closely as possible to the class-based view ListView, and so I ended up with this:
from django.core.paginator import Paginator, InvalidPage
from django.http import Http404
from django.utils.translation import gettext as _
from wagtail.core.models import Page
class ArticleListPage(Page):
# Some Page variables set here. #
# Pagination variables:
paginator_class = Paginator
paginate_by = 10
page_kwarg = 'page'
paginate_orphans = 0
allow_empty = False
def get_context(self, request):
context = super().get_context(request)
queryset = Page.objects.live()
paginator, page, queryset, is_paginated = self.paginate_queryset(
queryset, self.paginate_by, request)
context.update({
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset,
})
return context
def paginate_queryset(self, queryset, page_size, request):
"""
Adapted from the ListView class-based view.
Added the request argument.
"""
paginator = self.paginator_class(
queryset,
self.paginate_by,
orphans=self.paginate_orphans,
allow_empty_first_page=self.allow_empty)
page_kwarg = self.page_kwarg
page = request.GET.get(page_kwarg) or 1
try:
page_number = int(page)
except ValueError:
if page == 'last':
page_number = paginator.num_pages
else:
raise Http404(_("Page is not 'last', nor can it be converted to an int."))
try:
page = paginator.page(page_number)
return (paginator, page, page.object_list, page.has_other_pages())
except InvalidPage as e:
raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
'page_number': page_number,
'message': str(e)
})
This will give you the same paginator, page_obj, is_paginated and object_list variables in your template that you would get with a normal Django ListView.
(Using python 3, Django 2.1 and Wagtail 2.3.)

How can I raise Validation Error for a FileField

I have a form field like this
class FeedForm(ModelForm):
files=form.FileField(validators=[validate_file_extension])
class Meta:
model=Feed
fields=('text','auth','files',)
with the validator used to allow specific file types:
validator.py
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.png', '.xlsx', '.xls']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
I want to raise the above Validation Error in my template,how can I go about it?
views.py that generate form:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
feed = form.save(commit=False)
feed.user = User.objects.get(pk=7)
feed.pub_date=timezone.now()
#instance = Feed(files=request.FILES['files'])
# feed.files=request.FILES['files']
feed.save()
return redirect('home')
else:
form = form_class()
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
feedz = paginator.page(1)
except EmptyPage:
feedz = paginator.page(paginator.num_pages)
#return redirect('home')
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,})
views that the form is on using an include tag:
def home(request):
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
feedz = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
feedz = paginator.page(paginator.num_pages)
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,},context_instance=RequestContext(request))
html that generates the form:post_feed.html
<form role="form" action="{% url 'post_feed' %}" enctype="multipart/form-data" method="post">
{% csrf_token %}
<div class="mdl-textfield mdl-js-textfield ">
{{form.text}}
<label class="mdl-textfield__label" for="{{form.text.id_for_label}}">Cheated on?Blow the whistle here</label>
</div>
<div class="mdl-select mdl-js-select mdl-select--floating-label">
<label class="mdl-select__label" for="{{form.auth.id_for_label}}">Authority addressed to:<br/></label>
{{form.auth}}
</div><br/>
{{form.files}}
<br/> {{form.files2}}
<br/> {{form.files3}}
<br/><br/> <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised mdl-button--colored">Post</button>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{error|escape}}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
</form>
The html that has the above form on using an include tag
{% include "post_feed.html" %}
<h2>Feed Stream</h2>
{% for feed in feedz %}
<strong> {{feed.full_name_of_poster|title}} </strong> |
{% if feed.resolved == True %}
RESOLVED
{% else %}
UNRESOLVED
{% endif %}
<p> To:{{feed.auth}} </p>
<p>{{feed.text}} </p>
Full details
<p id='count'> {{feed.total_concerns}} concern{{feed.total_concerns|pluralize:'s'}} &nbsp {{feed.no_of_comments}} comment{{feed.no_of_comments|pluralize:'s'}} </p>
<p> {{feed.pub_date|naturaltime|capfirst}} </p>
<hr/>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if feedz.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ feedz.number }} of {{ feedz.paginator.num_pages }}.
</span>
{% if feedz.has_next %}
next
{% endif %}
</span>
</div>
{% endblock %}
I have gone through the docs but no breakthrough,Kindly help me out.Thanks in advance
The usual format for a function based view that handles a form is:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
# process the form then redirect
...
return redirect('home')
else:
# You don't actually need this else statement here
print form.errors
else:
# create blank form for GET requests
form = form_class()
# Now return a response for GET requests and invalid POST requests
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
return render(request , 'index.html' ,{'feeds':feeds,'form':FeedForm(),'feed_detail':feed_detail,})
So you just need to change the indentation at the end of the view, so that you return a response for invalid POST requests as well.
Django will automatically display any validation errors if you use {{ form }} in your template. If you render the fields individually, then see the docs for rendering fields manually for how to include errors manually.

Django Filtering A Blog Based on Tags

I'm trying to filter my blog based on tags. I've managed to work out how to display all the tags, however now I want the user to have the ability to click on a tag and bring up a filter list of blog posts based on that tag.
I'm getting an error:
ValueError invalid literal for int() with base 10: 'testtag'
url.py
urlpatterns = [
# Examples: /blogs
url(r'^tags$', 'blog.views.tags', name='tags'),
url(r'^tags/(?P<blog_tagslug>[\w-]+)$', 'blog.views.tagslist', name='tagslist'),
views.py
def tags(request):
blog_obj = Tag.objects.all()
paginator = Paginator(blog_obj, 5)
page = request.GET.get('page')
try:
blog_list = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
blog_list = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
blog_list = paginator.page(paginator.num_pages)
template_hash = {'blog_list':blog_list}
return render(request,'blog/tags.html', template_hash)
def tagslist(request, blog_tagslug):
#blog = Blog.objects.get(pk=blog_id)
#blog = Tag.objects.all().filter(tagslug=blog_tagslug)
blog = Blog.objects.all().filter(tags=blog_tagslug)
paginator = Paginator(blog, 2)
page = request.GET.get('page')
try:
blog_list = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
blog_list = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
blog_list = paginator.page(paginator.num_pages)
template_hash = {'blog_list':blog_list}
return render(request,'blog/index.html', template_hash)
tags.html (works fine)
<h1>All Tags</h1>
{% if blog_list %}
<ul>
{% for blog in blog_list %}
{{ blog.image.thumbnail.url }}
<li>{{ blog.tagslug }}</li>
{{ blog.tags.all|join:", " }} <br>
{% endfor %}
</ul>
{% else %}
<p>No blogs are available.</p>
{% endif %}
<div class="pagination">
<span class="step-links">
{% if blog_list.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ blog_list.number }} of {{ blog_list.paginator.num_pages }}.
</span>
{% if blog_list.has_next %}
next
{% endif %}
</span>
</div>
tagslist.html (doesn't work gets error)
<h1>Blog Index</h1>
{% if blog_list %}
<ul>
{% for blog in blog_list %}
{{ blog.image.thumbnail.url }}
<li>{{ blog.blog_title }}</li>
{{ blog.tags.all|join:", " }} <br>
{% endfor %}
</ul>
{% else %}
<p>No blogs are available.</p>
{% endif %}
<div class="pagination">
<span class="step-links">
{% if blog_list.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ blog_list.number }} of {{ blog_list.paginator.num_pages }}.
</span>
{% if blog_list.has_next %}
next
{% endif %}
</span>
</div>
models.py
from django.db import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.conf import settings
# Create your models here.
class Image(models.Model):
name = models.CharField(max_length = 255)
image = models.ImageField(upload_to="%Y/%m/%d",max_length=500,blank=True,null=True)
thumbnail = models.ImageField(upload_to="%Y/%m/%d",max_length=500,blank=True,null=True)
def __str__(self):
return self.name
class Tag(models.Model):
tagslug = models.SlugField(max_length=200, unique=True)
def __str__(self):
return self.tagslug
class Author(models.Model):
authorname = models.CharField(max_length=200, null=True)
def __str__(self):
return self.authorname
class Blog(models.Model):
blog_title = models.CharField(max_length = 200)
author = models.ForeignKey(Author)
image = models.ForeignKey(Image)
blog_content = models.TextField()
slug = models.SlugField(max_length=200, unique=True)
publish = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
tags = models.ManyToManyField(Tag)
user_id = models.ForeignKey(User)
def __str__(self):
return self.blog_title
class Comment(models.Model):
comment_content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
blog_id = models.ForeignKey(Blog)
user_id = models.ForeignKey(User)
def __str__(self):
return '{0}, {1}'.format(self.comment_content, self.created)
The problem is that tags expect a list of Tag objects whereas you pass a string. You should filter blogs by tag's slug as follows:
blog = Blog.objects.all().filter(tags__tagslug=blog_tagslug)

Django Paginator Error

I'm been trying to implement django paginator into my whiteboard app so I can split the pictures into different pages.
The problem occurs when I attempt to move across different pages.I limited each page to 1 objects and uploaded few pictures to test if the pagination works between pages but when I try to move across different pages using the pagination method, it doesn't respond.
http://img854.imageshack.us/img854/3303/94627386.jpg
I'm been researching and testing for solutions to this problems through the django pagination docs and I think problem lay at the pagination module method at my template.
My views.py
def Boat(request ,animal_id):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
picture = Picture.objects.filter(board=animal_id)
paginator = Paginator(picture,1)
page = request.GET.get('page')
try:
picture = paginator.page(page)
except PageNotAnInteger:
picture = paginator.page(1)
picture = paginator.page(paginator.num_pages)
return render(request,'boat.html',{'picture':picture })
My boat.html
{% if picture.object_list %}
<ul>
{% for pet in picture.object_list %}
{% if pet.image %}
<br>
<img src= "{{ pet.image.url }}" </a>
<br>
</a>
</li>
{% endif %}
<br>
View Comment Like<br/>
{% for c in picture %}
{% ifequal c.picture.id pet.id %}
<br>{{ c.body }}</li>
<br>{{ c.created}}</li>
<br>{{ c.user}}</li>
{% endifequal %}
% endfor %}
{% endfor %}
</ul>
{% endif %}
Add Pictures to your board<br/>
{% if number %}
{{number}}
{% endif %}
Return back to Profile<br/>
<br><br><br><br><br>
<div class="pagination">
<span class="step-links">
{% if picture.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ picture.number }} of {{ picture.paginator.num_pages }}.
</span>
{% if picture.has_next %}
next
{% endif %}
</span>
</div>
Parts of my module
class Picture(models.Model):
user = models.ForeignKey(User)
board = models.ForeignKey(Board,blank=False,null=False,related_name='board')
image = models.FileField(upload_to="images/",blank=True)
description = models.TextField()
is_primary = models.BooleanField(default=False)
def __unicode__(self):
return self.description
def Boat(request ,animal_id):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('world:LoginRequest'))
picture = Picture.objects.filter(board=animal_id)
paginator = Paginator(picture,1)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
picture = paginator.page(page)
except (EmptyPage, InvalidPage):
picture = paginator.page(paginator.num_pages)
picture = paginator.page(paginator.num_pages)
return render(request,'boat.html',{'picture':picture })
#this is view
#this is views files
#login_required(login_url='/login')
# class Base_page_list2(ListView):
def Base_page_list(request,*args, **kwargs):
# tiket = Tiket.objects.all()
# lastest_tiket =Tiket.objects.order_by('-id').all()[:8]
tiket_list = Tiket.objects.all()
paginator = Paginator(tiket_list,2)
page = request.GET.get('page')
page_obj = paginator.get_page(page)
context ={
'tiket':None,
'page_obj':page_obj,
}
context['tiket']=['page_obj']
if request.user.is_superuser:
context['tiket']= Tiket.objects.all()
elif not request.user.is_hrm:
raise Http404('شما نمی توانید به این صحفه دسترسی داشته باشید')
elif request.user.is_mis :
context['tiket']= Tiket.objects.filter(status_tag='s')
elif request.user.is_mali:
context['tiket']=Tiket.objects.filter(status_tag='m')
elif request.user.is_mosh:
context['tiket']=Tiket.objects.filter(status_tag='c')
elif request.user.is_modir:
context['tiket']=Tiket.objects.filter(status_tag='b')
elif request.user.is_kz:
context['tiket']=Tiket.objects.filter(status_tag='k')
elif request.user.is_pa:
context['tiket']=Tiket.objects.filter(status_tag='p')
else:
context['page_obj']['tiket']=Tiket.objects.filter(author=request.user)
return render(request,'hrm_account/base.html',context)
`enter code here`error
File "/home/ali/Desktop/testsharen2/sharen/sharen_hrm/views.py", line 128, in Base_page_list
context['page_obj']['tiket']=Tiket.objects.filter(author=request.user)
TypeError: 'Page' object does not support item assignment