how to make flask pagination keep the query condition - flask

here is my view function:
def get_user_info():
form = UserInfoForm()
query = UserInfo.query
if form.validate_on_submit():
query = query.filter_by(sex=form.sex.data)
flag = False
page = request.args.get('page', 1, type=int)
pagination = query.paginate(page=page, per_page=10, error_out=False)
return render_template("user_info.html", form=form,data=pagination.items, pagination=pagination)
and here is part of my html:
<form class="form-inline" action="{{url_for('.get_user_info')}}", method="post">
{{ form.csrf_token }}
<div class="panel-body">
<div class="form-group">
{{ form.sex.label }}:
{{ form.sex(class="form-control") }}
</div>
<div class="form-group">
{{ form.submit(class="btn btn-primary") }}
</div>
</div>
and here is my pagination macro:
{% macro pagination_widget(pagination, endpoint) %}
{% if pagination.total != 0 %}
<ul class="pagination">
<li{% if pagination.page == 1 %} class="disabled"{% endif %}>
<a href="{% if pagination.page != 1 %}{{ url_for(endpoint, page=1, **kwargs) }}
{% else %}#{% endif %}">««</a>
</li>
<li{% if not pagination.has_prev %} class="disabled"{% endif %}>
<a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.page - 1, **kwargs) }}
{% else %}#{% endif %}">«</a>
</li>
{% for p in pagination.iter_pages() %}
{% if p %}
<li {% if p == pagination.page %} class="active"{% endif %}>
{{ p }}
</li>
{% endif %}
{% endfor %}
<li{% if not pagination.has_next %} class="disabled"{% endif %}>
<a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.page+1, **kwargs) }}
{% else %}#{% endif %}">»</a>
</li>
<li{% if pagination.page == pagination.pages %} class="disabled"{% endif %}>
<a href="{% if pagination.page != pagination.pages %}{{ url_for(endpoint, page=pagination.pages, **kwargs) }}
{% else %}#{% endif %}">»»</a>
</li>
</ul>
{% endif %}
{% endmacro %}
I use a selectfiled sex in my page, when I select male in my page, I get the paginate object and my first page user is all male.But when I click next page, the results will have both male and female, I just want it like the first page, it has only male user info. Thanks.

I have resolved my problem today.
There are *args, and **kwargs for any macro, so I can pass parameters of query condition to it and in my view functions use request.args.get() to obtain parameters and set it to form.

Related

Django Pagination - Object list not looping in template

I'm attempting to use pagination on my notifications page for a user (list of all notifications). When I add the code for pagination:
def notificationList(request, pk):
notifications = Notification.objects.all()
paginator = Paginator(notifications, 5)
page = request.GET.get('page')
try:
notifications = paginator.page(page)
except PageNotAnInteger:
notifications = paginator.page(1)
except EmptyPage:
notifications = paginator.page(paginator.num_pages)
context = {'notifications': notifications }
return render(request, 'user/notifications.html', context)
The result is this:
However, when I comment out all pagination related code in views.py, all the notifications appear on the page (pagination appears). So I know it's not that I'm not accessing my notification object list incorrectly/returning an empty queryset. Here is the notifications.html pagination code:
{% if notifications.has_other_pages %}
<ul class="pagination justify-content-center mb-4">
{% if notifications.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">«</span></li>
{% endif %}
{% for i in notifications.paginator.page_range %}
{% if notifications.number == i %}
<li class="active page-item"><span class="page-link">{{ i }} <span class="sr-only page-item">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if notifications.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.next_page_number }}">»</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">»</span></li>
{% endif %}
</ul>
{% endif %}
Here is where I render the notifications in the template:
{% for notification in notifications %}
<div class="row">
<div class="col">
{% if notification.read == False %}
<span class="badge badge-primary">New</span>
{% elif notification.read == True %}
<span class="badge badge-success">Read</span>
{% endif %}
</div>
<div class="col">
<a class="btn btn-sm btn-info" href="{% url 'offer-details' notification.offer_id %}">View</a>
</div>
<div class="col">
{% if notification.type_of_notification == "O" %}
<p>An offer has been made for one of your repairs!</p>
{% elif notification.type_of_notification == "P" %}
<p>A payment has been made on a repair!</p>
{% elif notification.type_of_notification == "OR" %}
<p>Sorry, your offer for a repair has been rejected.</p>
{% elif notification.type_of_notification == "OC" %}
<p>An offer for your repair has been canceled!</p>
{% endif %}
</div>
<div class="col">
{{notification.created_at}}
</div>
</div>
<hr>
{% endfor %}

Listing Tags of a Post in Django CMS and Aldryn NewsBlog

I am trying to figure out how to display tags belonging to an article created within Aldryn NewsBlog plugin. Unfortunately, I cannot find any documentation on how do it.
I was able to display categories using the following code.
<span style="margin: 0; display: block">
<h4 style="display:inline-flex">Categories:</h4>
{% for category in article.categories.all %}
{{ category.name }} {% if not forloop.last %}, {% endif %}
{% endfor %}
</span>
For tags, I am using this code:
<span style="margin: 0; padding-bottom: 0; display: block">
<h4 style="display:inline-flex">Tags:</h4>
{% for tag in article.tag %}
{{ tag.name }} {% if not forloop.last %}, {% endif %}
{% endfor %}
</span>
What am I doing wrong? Could anyone tell me how to display tags?
this is the official tags template of aldryn-newsblog, it worked for me:
{% load i18n apphooks_config_tags %}
<div class="aldryn aldryn-newsblog aldryn-newsblog-tags">
<ul class="list-unstyled">
<li{% if not newsblog_tag %} class="active"{% endif %}>
{% trans "All" %}
</li>
{% for tag in tags %}
<li{% if newsblog_tag.id == tag.id %} class="active"{% endif %}>
<a href="{% namespace_url "article-list-by-tag" tag.slug namespace=instance.app_config.namespace default='' %}">
{{ tag.name }}
<span class="badge">{{ tag.article_count }}</span>
</a>
</li>
{% endfor %}
</ul>
https://github.com/aldryn/aldryn-newsblog/blob/master/aldryn_newsblog/boilerplates/bootstrap3/templates/aldryn_newsblog/plugins/tags.html
you're right, that is what you're looking for, with article.tags.all:
{% if article.tags.exists %}
<ul style="margin-left: 0">
{% for tag in article.tags.all %}
<li class="tags">{{ tag.name }}</li>
{% if not forloop.last %}<span class="separator tags-separator">|</span> {% endif %}
{% endfor %}
</ul>
{% endif %}

is_paginated not working properly for class based views in Django

book_list.html
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if book_list %}
<ul>
{% for book in book_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% endif %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% endblock %}
class in views.py :
class BookListView(generic.ListView):
model = Book
paginate_by = 2
queryset =Book.objects.all()
urls.py :
urlpatterns =[
url('^$',views.index, name ='index'), # matching with an empty string
url('^books/$',views.BookListView.as_view(),name ='books'), #the one to which I am adding the paginator
url('^book/(?P<pk>\d+)/$',views.BookDetailView.as_view(),name='book-detail'),
]
Book model :
class Book(models.Model):
title=models.CharField(max_length=100)
author = models.ForeignKey('Author',on_delete=models.SET_NULL,null = True)
summary = models.TextField(max_length=200,help_text="Enter the description")
isbn = models.CharField('ISBN',max_length=13 ,help_text='13 Character ISBN number' )
genre = models.ManyToManyField(Genre,help_text = 'selct a genre for this book')
class Meta:
ordering =["title"]
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book-detail',args=[str(self.id)] )
The book_list gets rendered perfectly, the problem is with the paginator, the is_paginated condition is not working and it executes the else statement, I have been trying for more than 3 hours, but couldn't find a solution, What Am I missing here ?
Django version : 1.11.2
Python : 3.5
Edit :
update 1: The problem was the paginate_by value was two, and the total items to display was also two hence it didn't initiate the is_paginated tag,It worked fine when I added one item more than paginate_by value.
use this, you had some problem with the if condition
{% extends "base.html" %}
{% block content %}
<h3> Available books </h3>
{% if object_list %}
<ul>
{% for book in object_list %}
<li> {{book.title }} <small> by {{book.author }}</small></li>
<p>{{ book.summary }}
{% endfor %}
<ul>
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% else %}
<h4> pagination not working</h4>
{% endif %}
{% else %}
<h4> No book</h4>
{% endif %}
{% endblock %}

How to recognize the first loop call in if statement?

I have code in template:
{% for p in products %}
{% if p.parent == None %}
<li class="{% if forloop.first %}active{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}
In my case class "active" shows me in li with parent != None. I can't use [...]filter(parent=None) in view as I must have a complete list of products.
The problem is that if first object.parent in products =! None Django will think that the first iteration happened so that I will never add active to my class.
So I want to check when the first iteration with successful if statement happened. Any ways to do this?
You could recover the first element in the view in python, add it to the context and then test in your template :
{% for p in products %}
{% if not p.parent %}
<li class="{% if p == first_element %}active{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}
{% with is_first=True %}
{% for p in products %}
{% if p.parent == None %}
<li class="{% if is_first %}active{% endwith % }{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}
Can not test now - but perhaps that work!
You can put this on the objects themselves or as extra variable, when you build the context. Do code like this:
e.g. instead of:
ctx['products'] = Product.objects.all()
do something like this:
ctx['products'] = list(Product.objects.all())
is_first = True
for p in ctx['products']:
p.is_active = p.parent is None and is_first:
is_first = False
Then in the template, just do:
<li class="{% if p.is_active %}active{% endif %}">
{{ p.name|upper }}
</li>
If you don't want to write on the object, use extra variable
ctx['products'] = list(Product.objects.all())
is_first = True
for p in ctx['products']:
if p.parent is None and is_first:
ctx['active_id'] = p.id
break
Then in the template, just do:
<li class="{% if p.id == active_id %}active{% endif %}">
{{ p.name|upper }}
</li>
You can also use forloop.counter like this
{% for p in products %}
{% if forloop.counter == 0 %}
<li class="{% if is_first %}active{% endwith % }{% endif %}">
{{ p.name|upper }}
</li>
{% endif %}
{% endfor %}

Django comments pagination isnt working

there is a trouble I'm new to django and there is an issue I can't understand,
there is a view:
def article(request, article_id = 1, comments_page_number = 1):
all_comments = Comments.objects.filter(comments_article_id = article_id)
paginator = Paginator(all_comments, 2)
comment_form = CommentForm
args = {}
args.update(csrf(request))
args['article'] = Article.objects.get(id = article_id)
args['comments'] = paginator.page(comments_page_number)
args['form'] = comment_form
args['username'] = auth.get_user(request).username
return render_to_response('article.html', args)
there is a template article.html
{% extends 'main.html' %}
{% block article %}
<h4>{{article.article_date}}</h4>
<h2>{{article.article_title}}</h2>
<p> {{article.article_body}}</p>
<hr>
<div class="large-offset-1 large-8 columns">
<p>Комментарии: </p>
{% for comment in comments %}
<p>{{comment.comments_text}}</p>
<hr>
{% endfor %}
{% if username %}
<form action="/articles/addcomment/{{article.id}}/" method="POST" >
{% csrf_token %}
{{form }}
<input type="submit" class="button" value="Add comment">
</form>
{% endif %}
</div>
<div class="row">
<div class="large-3 large-offset-5 columns">
<ul class="pagination">
{% if comments.has_previous %}
<li class="arrow">«</li>
{% else %}
<li class="arrow unavailable">«</li>
{% endif %}
{% for page in comments.paginator.page_range %}
{% if page == comments.number %}
<li class="current">{{ page }}</li>
{% else %}
<li>{{ page }}</li>
{% endif %}
{% endfor %}
{% if comments.has_next %}
<li class="arrow">»</li>
{% else %}
<li class="arrow unavailable">»</li>
{% endif %}
</ul>
</div>
</div>
{% endblock %}
this is my article/urls.py
urlpatterns = patterns('',
url(r'^articles/get/(?P<article_id>\d+)/$','article.views.article'),
url(r'^articles/get/(?P<article_id>\d+)/comments/(\d+)/$', 'article.views.article'),
)
after that on my article page appeared an pages pagination, but when I'm clicking on the second page, for example, it it is just changing my url, but new comments are not appearing, just old ones.
What should I do to do this right? Thank you very much!
Your variable name comments_page_number uses always the default value. Name your second parameter in the url route to match this variable name.
you need :
url(r'^articles/get/(?P<article_id>\d+)/comments/(?P<comments_page_number>\d+)/$', 'article.views.this_article'),