Django Paginator not working beyond first page - python

As mentioned in the title, my paginator doesn't show anything when I click to go to a page beyond the first.
First, let me describe my page in general:
Its function is to get a request input from the user specifying the period interval from which he wants to see a bunch of "call records" along with other filters (this is important). So essentially there's a start and end date from the request and I use it to filter my objects.
The link to "page2" is something like: "localhost:8000/?page=2" and redirects to my existing page but without any data. It's obvious now that the link to the next page should include the other parameters such as start_date=xxxx-xx-xx, or else it wouldn't work.
Here's part of my view.py and I took out a lot of lines to make it brief, the code runs fine:
if request.GET:
filter_form = ReportFilterForm(request.GET)
if filter_form.is_valid():
start = filter_form.cleaned_data["start_date"]
end = filter_form.cleaned_data["end_date"]
#a bunch of omitted lines that use the form to filter
paginator = Paginator(queryset, 100)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
call_logs = paginator.page(page)
except (EmptyPage, InvalidPage):
call_logs = paginator.page(paginator.num_pages)
else:
filter_form = ReportFilterForm()
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,
})
My template xxxx.html, just the paginator section, which is pretty standard, taken from the documentation:
{% if call_logs.paginator.num_pages %}
<div class="pagination">
<span class="step-links">
{% if call_logs.has_previous %}
<<
{% endif %}
<span class="current">
Page {{ call_logs.number }} of {{ call_logs.paginator.num_pages }}
</span>
{% if call_logs.has_next %}
>>
{% endif %}
</span>
</div>
{% endif %}
My question is how do I get the current window URL using django templates and not javascript?
Thank you.

You could add the full path to the context from the request object if I understand you correctly:
return render_to_response('xxxx.html',
{'queryset': queryset,
'filter_form': filter_form,
'call_logs': call_logs,,
'magic_url': request.get_full_path(),
})

My question is how do I get the
current window URL using django
templates and not javascript? Thank
you.
it's not necessary the right way to do it, but you can check this post
but i will suggest that you shouldn't mix the filter with the pagination.
rather that you can use AJAX when doing filtering you can create a new function that deal with filtering alone or you can just use the same function and test if request.is_ajax(): , like that when a users filter the contain you will have your filter data (start_date,end_date ) in the URL.
and now when a user want to pass to the next page you already have the filtered argument in the url that you can use to create a queryset that will be pass to the Paginator.
And to deal with the javascript not active you can replace AJAX with a simple POST form and just remember don't mix the filtering with the pagination :)
Hope this will Help :)

Related

Pagination when search and results are on the same page

I have a template where the users pass a query and select a couple of checkboxes (these can range from 1-100). Then, my view does the following:
def search(request):
results_list = search(request.GET.get("q", ""), request.GET.getlist("c"))
# Pagination
paginator = Paginator(results_list, 10)
page = request.GET.get("page")
results = paginator.get_page(page)
return render(
request,
"web/search/show.html",
{
"query": query,
"results": results,
},
)
The issue arrises because both the search and the presentation of the results happen on the same page. Therefore, when I want to include pagination, in my template, I have to do the following:
<div class="pagination">
<div class="step-links">
{% if results.has_previous %}
Previous
{% endif %}
{% if results %}
<span class="current">
Page {{ results.number }} of {{ results.paginator.num_pages }}
</span>
{% endif %}
{% if results.has_next %}
Next
{% endif %}
</div>
</div>
Please consider the usage of request.GET.urlencode because when the user wants to either go to the previous or next page the same query and checkboxes need to be passed. However, this creates a bug when the user goes past the second page, because the ?page=3&page=2 keep on piling up. Can someone point me in the right direction for solving this issue?
An easy solution would be to repeat every GET parameter you need to handle in the link rather than use the full querystring, something like:
Next
A more elegant solution would be to create a Django template tag to build the URL based on the current state of the querystring, something like what is described in this article: Dealing With QueryString Parameters.

Django - Passing parameters from template to view not working

I'm trying to get my hands dirty with django and I started trying to make my own project. I'm currently having trouble passing parameters from my template to my views without using POST requests.
heres my code in the template
#in main.html
<div>
{{ event_results }}
{{ friends }}
</div>
{% for user in results %}
<div class="userblock">
<p class="user">{{ user.username }}</p>
<a href="/events/addFriend/{{user.username}}">
<button class="navbuttons" id="addfriend">Add as friend</button>
<a/>
</div>
{% endfor %}
#in urls.py
from django.conf.urls import patterns, url
from events import views, eventview
url(r'^addFriend/(<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),
)
#in views.py
def addFriend(request, requested_friend):
currentUser = User.objects.get(username=request.session['username'])
try:
list_of_friends = Friends.objects.get(username=currentUser)
except (KeyError, Friends.DoesNotExist):
return render(request, 'events/main.html', {'friends': requested_friend})
else:
return render(request, 'events/main.html', {'friends':list_of_friends})
So when I click on the button "Add friend" in main.html, it goes to the url.py and maps it to the function addFriend in views.py with the argument and from there it does its magic. However, it's not taking in the argument. I know I'm doing something wrong in the urls.py with the regex but im not sure what. Any advice is greatly appreciated. Thanks!
When you change (<requested_friend>[a-z]*) to (?P<requested_friend>[0-9A-Za-z_\-]+) than everything looks fine.
But remember to use + instead of * in the pattern. * matches also a empty string (addFriend// is matched) but with + the string must have at least one character (addFriend// isn't matched)
You can add $ on the end of url pattern r'^addFriend/(?P<requested_friend>[0-9A-Za-z_\-]+)/$' Here you can find why.
Also check if link in browser has correct value /events/addFriend/<user_name>/ maybe is something wrong with {{ user.username }}
You have error in urls.py. In named group pattern you miss ?P prefix. See doc for reference.
Instead of
url(r'^addFriend/(<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),
It should be:
url(r'^addFriend/(?P<requested_friend>[a-z]*)/', views.addFriend, name='addFriend'),

Remember form data for pagination

In my Flask application, I have a view which renders a table of items by using the Flask-SQLAlchemy pagination method. Great stuff so far. But I want to add sorting and filtering, so I created a form with selectboxes where the user can choose the sort and filter options.
When submitting the sort/filter on the page, the view works fine: the first page is sorted. But selecting another page on the page, the pagination is falling back to the original query. What should I do to save my sort/filter options during new page loads? Using flask.g has come up to me, but is it the correct way?
class ItemTableForm(Form):
sort_choices = [('id', 'ID'),
('name', 'Name'),
('status', 'Status')]
filter_choices = [('all', 'All'),
('instock', 'In stock'),
('sold', 'Sold')]
sort = SelectField(u'Sort by', choices=sort_choices)
filter = SelectField(u'Filter by', choices=filter_choices)
#app.route('/browse/<int:page>', methods=("GET", "POST"))
def browse(page):
form = ItemTableForm()
if form.validate_on_submit():
query = Item.query.order_by(getattr(Item, form.sort.data))
else:
query = Item.query
pagination = paginate(query, page)
return render_template('browse.html', pagination=pagination, form=form)
# My template contains this form and a regular HTML table
<form action="{{ url_for('browse') }}" method="POST">
{{ form.hidden_tag() }}
{{ form.sort.label }} {{ form.sort() }}
{{ form.filter.label }} {{ form.filter() }}
<button type="submit" class="btn">Submit</button>
</form>
You can use url parameters to pass the info about sorting. Say user selects sorting by name. Then add this at the end of url
your_url?sort=name
Then you can access it as
value = request.args.get('name','')
Simply pass sorting variable value to the template where you append sort value to the next url.
Edit:
To create such url in Flask, do this:
url_for('url_view_name', sort='name')
This will return the url with sort appended as query argument. Check out the flask documentation here to know more about url building
You could do this with Javascript. Since the page number is part of your URL, you could have javascript change the action of the form that changes pages to submit to a URL with the desired page number instead of the current page.
Just to clarify, when the user clicks the "next" link/button or page number, use Javascript to change the action of the html form so that it posts the form to the desired page instead of the current page.

How to describe URL in Django - still need an answer

I'm trying to make a simple search and return results in a paginated form. Whenever I try to go to the second page, my search term is lost and thus my second page has no results.
I've found and followed the Pagination example in the Djangoproject tutorial, but I haven't found an example on how to write my URL for the search view.
I've used POST method in my form previously, for when I had little data to display (although now, after a bit of research, I know the usage difference between GET and POST). When I gained lots more data, I was constrained to use Pagination. Thus, I've changed my form method to GET but here is my problem, I don't know how to describe my URL so the data is sent to the right view.
I've tried to make it work with POST but with no success. Finally I decided to stick to GET example but stumbled on this URL thing that's keeping me back.
Here is the code in the template and the URLs file:
search.py:
<form method="GET" id="searchForm" action="/search/?page=1">
{% csrf_token %}
<input type="text" id="billSearched" name="q_word">
<input type="submit" value="{% trans "Look for" %}">
</form>
urls.py:
urlpatterns = patterns('',
url(r'^$','ps.views.bills',name="bills"),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^search/$','ps.views.search',name="search"),)
I've tried many forms for the URL but none have succeeded.
i.e.:
url(r'^search/(?P<page>\d+)/$','ps.views.search',name="search")
url(r'^search/','ps.views.search',name="search")
url(r'^search/(?P<page>\d+)/(?P<searchTerm>\w*)','ps.views.search',name="search")
Any explanation / solution would be really appreciated. Thank you in advance!
UPDATE:
def search(request):
searchTerm = ""
page = 1
import pdb
pdb.set_trace()
if 'q_word' in request:
searchTerm = request.GET['q_word']
if 'page' in request:
page = request.GET['page']
found_bills = Bill.objects.filter(name__icontains = searchTerm)
paginator = Paginator(found_bills,25)
try:
current_page = paginator.page(page)
except PageNotAnInteger:
current_page = paginator.page(1)
except (EmptyPage, InvalidPage):
current_page = paginator.page(paginator.num_pages)
bills_list = list(current_page.object_list)
return render_to_response('results.html',{"bills_list":bills_list,"current_page":current_page,},context_instance=RequestContext(request))
UPDATE #2:
If I use pdb I can see that there is no data being passed from the client to the server. Got to work on that, but still, any information and/or hints would be really appreciated as they can shorten my search time :)
(Pdb) request.GET
<QueryDict: {u'page': [u'1']}>
If your form's method is GET, you cannot append a query string to the action, because the browser will overwrite it. You can only do that if your form method is POST.
Change your form to this:
<form method="GET" id="searchForm" action="/search/">
<input type="text" id="billSearched" name="q_word">
<input type="submit" value="{% trans "Look for" %}">
</form>
In your view:
from django.shortcuts import render
def search(request):
if 'q_word' in request:
searchTerm = request.GET['q_word']
found_bills = Bill.objects.filter(name__icontains = searchTerm)
page = request.GET.get('page')
paginator = Paginator(found_bills,25)
try:
current_page = paginator.page(page)
except PageNotAnInteger:
current_page = paginator.page(1)
except (EmptyPage, InvalidPage):
current_page = paginator.page(paginator.num_pages)
# bills_list = list(current_page.object_list) - not needed
return render(request,
'results.html',{"results":current_page,"term": searchTerm})
In results.html:
{% for bill in results %}
# .. display bill stuff
{% endfor %}
{% if results.has_previous %}
previous
{% endif %}
{% if results.has_next %}
next
{% endif %}
What do you mean by 'describe' your url? Your urls.py look fine. Did you drop a debugger into your ps.views.search() function to verify that it is hitting? Did you look at your debug server logs to make sure the right url is being requested from the browser?
you can either have r'^search/$' and access the page param as request.GET['page'] or you can pass in the param to your view function like url(r'^search/(?P<page>\d+)/$ which would mean search would take 2 params request and then page. If passing in the page param you need to change your form URL to be
<form method="GET" id="searchForm" action="/search/1">
Instead of having page be a GET param
I don't see anything wrong with your syntax for any of the urls you've listed.
https://docs.djangoproject.com/en/1.3/topics/pagination/#using-paginator-in-a-view
If you are using url(r'^search/(?P<page>\d+)/$' make sure that search takes a variable named page as a second argument. It is important to learn how to use the debugger too.
import pdb; pdb.set_trace() (or even better ipdb!), Drop that in your view to see if its hitting, If its not hitting check dev server to see what url is actually being requested.

Django template check for empty when I have an if inside a for

I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.

Categories

Resources