Pagination problem - django

I'm using this code for my pagination, and I'd like the user's choice to be persistent throughout the site (this has been solved so far)...the only problem now is that the session variable now is permanent until the session is cleared by closing the browser. Also, how can I get the adjacent pages displayed...like in the digg-style Django paginator. I haven't been able to make sense of how to implement this into my code.
The code is as follows:
from django.core.paginator import Paginator, InvalidPage, EmptyPage
def paginate(request, object_list, paginate_by=10):
try:
if "per_page" in request.session:
per_page = request.session["per_page"]
else:
request.session["per_page"] = int(request.REQUEST['p'])
per_page = request.session["per_page"]
request.session.set_expiry(0)
except:
per_page = 10
paginator = Paginator(object_list, per_page)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
items = paginator.page(page)
except (EmptyPage, InvalidPage):
items = paginator.page(paginator.num_pages)
return items
Then in my template I have this to render the pagination links:
<div class="pagination" align="center">
<span class="step-links">
{% if items.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ items.number }} of {{ items.paginator.num_pages }}
</span>
{% if items.has_next %}
next
{% endif %}
</span>
</div>

You can achieve this by enabling sessions.
I recommend reading through the chapter Sessions, Users, and Registration on the djangobook website.
Edit: Now that you've enabled sessions, I think the problem is the hyperlinks in the template. Use an ampersand to separate multiple parameters in a url, for example
next
Edit 2: I'm not sure if I understand what the problem is with the session expiry. The line that sets the session to expire when the browser closes is request.session.set_expiry(0). See the django docs on Using Sessions in views if you want to change that.
To make a Digg style paginator, you need to write a function that takes the current page number and the total number of pages, and returns a list of page numbers. Then, in the template, loop through the page numbers and construct links to the pages.
A list of lists of page numbers would allow you to split the page numbers into groups, eg
[[1,2], [20,21,22,23,24], [30,31]]

Related

How can I paginate list of dictionaries in django

I am working on Django pagination and trying to paginate my data which is in the form of dictionaries inside a list, I tried function based approach as per documentation
class MyUserData(TemplateView):
template_name = "myuserdata.html"
form = "userform"
def listing(request):
contact_list = Contact.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page.
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'list.html', {'page_obj': page_obj})
I am writing above function inside my class which is inheriting (TemplateView) now the problem is that it is reducing the number of results to 25 but when i click on next it doesn't show next page
<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>
Flow is like this the user will come and enter the start date and end date and click on submit and get's his history of data and the issue is user gets all his history if he selects longer date range which I want to paginate
this is how data is coming in the form of dictionaries inside list
[{'date':'2021/12/02','address':'minneapolis 111 NY','machine':'TR'},{'date':'2021/12/03','address':'minneapolis 111 NY','machine':'MR'},{'date':'2021/12/02','address':'minneapolis 111 NY','machine':'PR'},{'date':'2021/12/02','address':'minneapolis 111 NY','machine':'CR'},{'date':'2021/12/12','address':'minneapolis 111 NY','machine':'RR'}]
This data is coming from api and not from django models.
I tried function based approach inside class which inherits the template view
is it possible that I can try this inside class, as per documentation if I am writing class I need to use ListView is it possible in Templateview? i have to use ListView only?
Assuming you have a list of dictionaries in a variable data:
from django.core.paginator import Paginator
paginator = Paginator(data, 3)
# 3 here is limit number, you can give dynamic value changing it to your required limit number
objects = paginator.page(1)
# 1 here is page number, you can give dynamic value changing it to your required page number
print(list(objects))
# This should print first 3 data as a list

Django using more than one forms in one page from same model

I want to use more than one forms in the same page from the same model.
Ok, lets take it easy.
I have Social modules that have 3 attributes (network, url and image) charfield.
I've added 4 values in Social database (Facebbok, Twitter, Youtube, Pinterest)
In the settings view (settings.html) i want to have all 4 forms (for Facebook, Twitter etc.) to edit them.
Something like that:
Facebook: text input (that contains the current facebook url)
Youtube: text input (that contains the current youtube url)
etc.
So when i go to settings.html i can change, update social url for all networks.
I have something like this for General Settings module (that have 3 fields, Title, Slug, Description and 1 attribute cuz the website have 1 title, 1 slug and 1 description). For this one is pretty simple i can use get_object_or_404 because Settings module have just 1 value and i can select it.. but the problem is Social Module have more values and i want to have on my page all forms from them so i can edit how ever i want.
views.py
def settings(request):
sidebar_items = Sidebar.objects.order_by('position')
social_items = Social.objects.order_by('network')
settings = get_object_or_404(Settings, pk = 1)
if request.method == "POST":
form_settings = SettingsForm(request.POST, instance = settings)
if form_settings.is_valid():
settings = form_settings.save(commit = False)
settings.save()
return HttpResponseRedirect('/dashboard/settings')
else:
form_settings = SettingsForm(instance = settings)
context = {'sidebar_items' : sidebar_items, 'form_settings' : form_settings, 'social_items' : social_items}
return render(request, 'dashboard/settings.html', context)
Django doesn't care how many forms you want to initialize in your view. If they're for the same model, you can use a formset. Otherwise, you can initialize and create objects however you want.
Example:
def your_view(request):
social_items = Social.objects.order_by('network')
forms = []
for index, social_item in enumerate(social_items):
forms.append(SocialForm(request.POST or None, instance=social_item,
prefix="form_{}".format(index)))
if request.method == 'POST':
for form in forms:
if form.is_valid():
form.save()
# do whatever next
return render(request, 'some-template.html', {'forms': forms})
You don't need three separate form tags in your template. You can submit all of the data in one post. Django will try to hydrate an instance of each model from the POST data, and return any errors if that fails.
In your template, you'll need to iterate over the form instances:
# some-template.html
<form action="." method="post" enctype="x-www-form-urlencoded">
{% for form in forms %}
<ol>
<li>
{{ form.network }}
{{ form.network.errors }}
</li>
<li>
{{ form.url }}
{{ form.url.errors }}
</li>
<li>
{{ form.image }}
{{ form.image.errors }}
</li>
</ol>
{% endfor %}
<button type="submit">Save</button>
</form>

How can django-cms plugins be displayed using pagination

I written two django-cms plugins to display image galleries and videos.
These are attached to CMS pages at /gallery/ and /videos/ where each template has a placeholder allowing the corresponding plugin to be included.
At that base level where I have gallery.html and video.html rendering all plugin instances to the page I would like to be able to attach endless for pagination.
This was a really simple task to achive pagination on images within a gallery because I have an apphook view in the gallery to collect a list of all the images and then it's as simple as {% pagingate images %} {% for image in images %} etc in the template.
However in a template where django-cms controls the collection & rendering of all the plugin instances and I lose that control, how can I paginate the plugins?
I've started down a route of using an apphook on the /gallery/ index, but to acomplish this I can imagine I'll need to stop django-cms doing what it does by default and what it should be left to do. So I need some guidance/advise on the best method for the job. Anyway, here's some code;
# views.py
def gallery_index(request, *args, **kwargs):
template = request.current_page.template
placeholder_id = request.current_page.placeholders.get(slot='gallery').id
gallery = Placeholder.objects.get(id=placeholder_id)
galleries = gallery.cmsplugin_set.all()
return render_to_response(
template,
{'galleries': galleries},
context_instance=RequestContext(request)
)
# gallery.html
<h3>GALLERIES</h3>
<div id="panel-area" class="gallery_grid">
<ul id="galleries" class="gridview" style="width: 800px;">
{% paginate galleries %}
{% for gallery in galleries %}
<li>{{ gallery }}</li> <!-- testing the pagination -->
{% endfor %}
{% placeholder "gallery" %}
</ul>
{% show_pages %}
# cms_plugins.py
class ImageGalleryPlugin(CMSPluginBase):
name = _('Image Gallery')
model = ImageGalleryPlugin
form = ImageGalleryAdminForm
render_template = 'single_gallery.html'
def render(self, context, instance, placeholder):
context.update({'gallery': instance,})
return context
# single_gallery.html
<li class="gallery_top">
<span class="title">
<a href="{% url 'image_gallery_page' page_id=request.current_page.id gallery_id=gallery.id %}">{{ gallery.event_date|date:"d/m/Y" }}<br/>
<p class="sub-text">View more of {{ gallery.event_name }}</p></a>
</span>
<img src="{{ gallery.display_random.gallery_display }}" alt="" border="0" />
</li>
My current solution is a jQuery solution, but I'd love it all to be controlled by django endless pagination for consistency in behaviour and design.
Been there. Pagination in Django CMS plugin is indeed problematic.
One possible way to solve the problem
Implement paginated API endpoint for fetching the objects. Use django.views.generic.list.ListView for example. It has nice built in pagination.
In CMS plugin, fetch objects from the API endpoint with AJAX. CMS plugin doesn't need to know which objects to render, it just needs to know where it can fetch the objects (the API endpoint).
This approach requires frontend code for fetching the correct objects, updating the UI, keeping track of the current page and so on, but can be (and has been) successfully used to implement paginated Django CMS plugins.
Here is my quick solution to add pagination into a django cms plugin
from cms.models.pagemodel import Page
from cms.plugin_base import CMSPluginBase
from django.http import Http404
from django.core.paginator import InvalidPage, Paginator
class MyPlugin(CMSPluginBase):
def render(self, context, instance, placeholder):
query_set = Page.objects.filter(is_page_type=False)
page = context['request'].GET.get('page') or 1
paginator, page, queryset, is_paginated = self.paginate_queryset(page, query_set, 6)
context.update({'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset
})
return context
def paginate_queryset(self, page, queryset, page_size):
paginator = Paginator(queryset, page_size)
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)
})

Paginating a Detail view in Django

I'm new to Django and for my first project I'm building a portfolio. And I need a little kick-start with pagination help. I have an "index" view with a list of projects and a detail view of each project. In the detail view, I want a feature to be able to paginate between each individual object. I've gone through the Pagination documenation and applied what I learned with my index view but when I try to do the same thing with my detail view I get a TypeError saying my "object of type 'Project' has no len().
Here's a sample of my views.py code for reference:
def index( request ):
all_projects = Project.objects.all().order_by( '-pub_date' )
paginator = Paginator( all_projects, 12 )
try:
page = int( request.GET.get( 'page','1' ))
except ValueError:
page = 1
try:
projects = paginator.page( page )
except (EmptyPage,InvalidPage):
projects = paginator.page( paginator.num_pages )
return render_to_response( 'portfolio/index.html', { 'all_projects':all_projects, 'projects':projects, 'MEDIA_URL':MEDIA_URL })
def detail( request, project_id ):
project = get_object_or_404( Project, id=project_id )
return render_to_response( 'portfolio/detail.html', { 'project':project, 'MEDIA_URL':MEDIA_URL } )
Apologies if I sound n00b-ish because I am, and gratitude in advance for any help. Also, I read this previous post but it didn't seem to apply to me because my views aren't Class-based.
Django has built-in get_next_by_FOO()/get_previous_by_FOO() methods which will return the next/previous object depeding on a datetime-field.
You could access them in the template by somethow like:
{{ project.get_next_by_pub_date.title }}
I would say that this is the preferred method over using pagination for that, as you will get a nice url you can define in your model's get_absolute_url for every item!
To paginate you need an instance of a QuerySet, not an object! So you should replace your get_object_or_404 call by a filter/all. So it would be basically the same as the list view, but just pass the number 1 to the paginator, as you already do!
I actually do not have that setup through Django's pagination. I used this code:
prev_issue = Issue.objects.filter(title=title).filter(number__lt=issue.number).order_by('-number')[:1]
next_issue = Issue.objects.filter(title=title).filter(number__gt=issue.number).order_by('number')[:1]
In your case, I would do something like this, but you would have to filter by something, too:
prev_project = Project.objects.order_by('-pub_date')[:1]
next_project = Project.objects.order_by('pub_date')[:1]
Then put the two in the context.
I also recommend django-pagination. I notice you probably want the pagination to stay on the index, correct? http://code.google.com/p/django-pagination/
You just have to mess with the template codes and it works great.
The great thing about Django is, that there is code for nearly every common programming problem, that you can download and use in your own project. (and most of the django packages are quiet well written too)
for pagination check out http://pypi.python.org/pypi/django-pagination
it's really easy to install and setup, so you do not have to think about pagination and focus on coding your software!
hope this helps, Anton
In my views.py
def ProjectDetail(request,pk):
context = {}
template = 'views/projectdetail.html'
project = ''
prev = Project.objects.filter(pk__lt=pk).order_by('-pk')[:1]
next = Project.objects.filter(pk__gt=pk).order_by('pk')[:1]
try:
print(prev[0].pk)
print(next[0].pk)
except:
pass
project = Project.objects.filter(pk=pk)
context['categories'] = ProjectCategory.objects.all()
paginator = Paginator(project, 1) # Show 25 contacts per page
page = request.GET.get('page')
try:
data = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
data = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
data = paginator.page(paginator.num_pages)
if prev:
context['prev'] = prev[0].pk
if next:
context['next'] = next[0].pk
context['data'] = data
return render_to_response(template, context,context_instance=RequestContext(request))
in my template i have
<div class="row">
<a {% if next %} href="{% url 'task:project-detail' next %}" class="btn btn-primary pull-right" {% else %} class="btn btn-primary pull-right disabled" {% endif %}>Next</a>
<a {% if prev %} href="{% url 'task:project-detail' prev %}" class="btn btn-primary pull-left" {% else %} class="btn btn-primary pull-left disabled" {% endif %} >Previous</a>
</div>

Django pagination and "current page"

I'm currently developing a Django application which will make use of the infamous "pagination" technique. I'm trying to figure out how the django.core.paginator module works.
I have an application with a Question model. I will be listing all of the questions using this paginator. There will be 20 questions per page.
def show_question(question_pk):
questions = Question.objects.all()
paginator = Paginator(questions, 20)
page = ... # Somehow figure out which page the question is on
return render_to_response('show_question.html', { 'page' : page })
In the view, where I list the different pages as "... 2, 3, 4, 5, 6, ..." I want to highlight the current page somehow, like many pages do.
There are really two things I want to know:
How do I make Django figure out which page the question is located at?
How would I write my template to properly "highlight" the currently visited page?
EDIT: Sorry, I forgot part of this question. I would also like any page except for the current one to be a link to /questions/{{ that_page.start_index }}. So basically every page link would link to the first question on that page.
Hmm... I see from your comment that you don't want to do the ol' GET parameter, which is what django.core.paginator was written for using. To do what you want, I can think of no better way than to precompute the page that each question is on. As an example, your view will end up being something like:
ITEMS_PER_PAGE = 20
def show_question(question_pk):
questions = Question.objects.all()
for index, question in enumerate(questions):
question.page = ((index - 1) / ITEMS_PER_PAGE) + 1
paginator = Paginator(questions, ITEMS_PER_PAGE)
page = paginator.page(questions.get(pk=question_pk).page)
return render_to_response('show_question.html', { 'page' : page })
To highlight the current page in the template, you'd do something like
{% for i in page.paginator.page_range %}
{% ifequal i page.number %}
<!-- Do something special for this page -->
{% else %}
<!-- All the other pages -->
{% endifequal %}
{% endfor %}
As for the items, you'll have two different object_lists to work with...
page.object_list
will be the objects in the current page and
page.paginator.object_list
will be all objects, regardless of page. Each of those items will have a "page" variable that will tell you which page they're on.
That all said, what you're doing sounds unconventional. You may want to rethink, but either way, good luck.
Django, at least from version 1.2, allows us to complete this task by using pure default pagination template tags.
{% for page in article_list.paginator.page_range %}
{% if page == article_list.number %}
{{ page }}
{% else %}
{{ page }}
{% endif %}
{% endfor %}
Where article_list is instance of
paginator = Paginator(article_list, 20)
try:
article_list = paginator.page(int(page))
except (EmptyPage, InvalidPage):
article_list = paginator.page(paginator.num_pages)
django-pagination should do what you want and comes wrapped in a pretty package you can just plug-in and use. It essentially moves the code from your views to the templates and a middleware.
EDIT: I just saw your edit.
You can get the current objects on a page using {% autopaginate object_list %}, which replaces object_list with the current objects for any given page. You can iterate through it and if you want the first, you should be able to treat it like a list and do object_list[0].
If you want to keep this within your views, you could do something like this:
def show_question(question_pk):
questions = Question.objects.all()
paginator = Paginator(questions, 20)
return render_to_response('show_question.html', { 'page' : paginator })
Within your template, you can access the current page you're on by doing:
# Gives you the starting index for that page.
# For example, 5 objects, and you're on the second page.
# start_index will be 3.
page.start_index
# You can access the current page number with:
# 1-based index
page.number
With that, you should be able to do everything you need.
There are a couple good examples here.