Yang
Yang

Reputation: 13

django pagination can not direct to next page

I want to use pagination to list data from database,but when I click next page button,it shows “local variable 'context' referenced before assignment”

I use filter to searching data from database first ,and use "REQUSET.POST" to get the data back。then send the data to another html。I think when I click next page,it will do all these again ,but I don't know how to code it。

Please help me to find out the problem,thank you!

Below is my code:

view.py

from django.template.loader import get_template
from django.template import RequestContext
from django.shortcuts import render,redirect
from django.http import HttpResponse,HttpResponseRedirect
from django.shortcuts import render,render_to_response
from datetime import datetime
from .form import DateRangeForm
from .models import Post
import tkinter.messagebox
from tkinter import *
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
# Create your views here.

def answer():
    showerror("Answer", "Sorry, no answer available")

def homepage(request):
    posts = Post.objects.all()
    now = datetime.now()
    context = {'posts':posts,'now':now}
    return render(request,'jishi.html',context)

def showpost(request,times):
    template=get_template('post.html')
   ##posts=Post.objects.all().values('customer')
    posts=Post.objects.filter(pub_date__year=2018)
    now = datetime.now()
    html = template.render(locals())
    return HttpResponse(html)

def foobar(request):
    date_sel1 = request.POST.get('datetime1',None)
    date_sel2 = request.POST.get('datetime2',None)
    if date_sel1!=None:
        posts = Post.objects.filter(pub_date__range=(date_sel1,date_sel2)).order_by("pub_date","time")
        paginator = Paginator(posts,6,1)
        page = request.GET.get('page')
        try:
            customer = paginator.page(page)
        except PageNotAnInteger:
            customer = paginator.page(1)
        except EmptyPage:
            customer = paginator.page(paginator.num_pages)
        context={'posts':customer}
    return render(request,'sheet.html',context)

html:

{% extends 'balance.html' %}

{% block content %}
       <div class='panel panel-default'>
         <div class='panel-heading'>
                   <h3>
               机时信息
           </h3>
         </div>
<div class="alert alert-warning" role="alert">
<table class="table table-bordered">
              <thead>
                <tr>
                  <th scope="col">条数</th>
                  <th scope="col">日期</th>
                  <th scope="col">时间</th>
                  <th scope="col">客户</th>
                </tr>
              </thead>
              <tbody>
                {% for post in posts %}
                <tr>
                  <th scope="row">{{forloop.counter}}</th>
                  <td>{{post.pub_date|date:"Y-m-d D"}}</td>
                  <td>{{post.time}}</td>
                  <td>{{post.customer}}</td>
                </tr>
                {% endfor %}
              </tbody>
</table>
<h3><a href='/blog/'>回首页</a></h3>
</div>
</div>
<nav aria-label="Page navigation">  
  <ul class="pagination">  
   {% if posts.has_previous %}  
    <li><a href="?cur_page=1"><<</a></li>  
    <li>  
      <a href="?cur_page={{ posts.pre_page }}" aria-label="Previous">  
        <span aria-hidden="true">«</span>  
      </a>  
    </li>  
   {% endif %}  
   {% for num in posts.paginator.page_range %}  
    {% if num == posts.cur_page %}  
        <li><a href="?cur_page={{ num }}">{{ num }}</a></li>  
    {% else %}  
        <li><a href="?cur_page={{ num }}">{{ num }}</a></li>  
    {% endif %}  
   {% endfor%}  
   {% if posts.has_next %}  
    <li>  
      <a href="?cur_page={{ posts.next_page }}" aria-label="Next">  
        <span aria-hidden="true">»</span>  
      </a>  
    </li>  
    <li><a href="?cur_page={{ posts.all_page }}">>></a></li>  
   {% endif %}  
  </ul>  
</nav> 
{% endblock %}

part of “post” html

<form action="/blog/create/?cur_page=1" method ="post" class="form-horizontal"  role="form">{% csrf_token %}            
        <div class="form-group row">
            <label for="dtp_input1" class="col-sm-2 control-label text-lg-left" style='font-family:微软雅黑;font-size:10pt;'>开始日期</label>
            <div class="input-group date form_date1 col-sm-5">
                <input class="form-control" size="16" type="text" name="datetime1" value="2018-01-01" required title="3 characters minimum"><br>
                <span class="input-group-addon col-md-2"><span class="glyphicon align-middle glyphicon-remove"></span></span>                                           
            </div>
            <input type="hidden" id="dtp_input1" value="" /><br/>
        </div>
        <div class="form-group row">
            <label for="dtp_input2" class="col-sm-2 control-label text-lg-left" style='font-family:微软雅黑;font-size:10pt;'>结束日期</label>
            <div class="input-group date form_date2 col-sm-5">
                <input class="form-control" size="16" type="text" name="datetime2" value="2018-01-01" required title="3 characters minimum"><br>
                <span class="input-group-addon col-md-2"><span class="glyphicon align-middle glyphicon-remove"></span></span>                       
            </div>
            <input type="hidden" id="dtp_input2" value="" /><br/>
        </div>
        <div class="form-group row">
            <div class="col-sm-2">
                <button class="btn btn-primary" type="submit" name="search" style='font-family:微软雅黑;font-size:10pt;'>确认查询</button>  
            </div>
            <div class="col-sm-2">
                <button class="btn btn-primary" type="submit" name="count" style='font-family:微软雅黑;font-size:10pt;'>机时统计</button>   
            </div>
        </div>
</form>

Upvotes: 0

Views: 1410

Answers (1)

bruno desthuilliers
bruno desthuilliers

Reputation: 77902

Here:

def foobar(request):
    date_sel1 = request.POST.get('datetime1',None)
    date_sel2 = request.POST.get('datetime2',None)

you're looking for your filter's values in request.POST. On a GET request those won't be set, so you'll get None as value for date_sel1. Then:

if date_sel1!=None:
    # do some things here to get your data and:
    context={'posts':customer}
return render(request,'sheet.html',context)

which means that when doing a GET request on the same view - which is what happens when you click the pagination links - date_sel1 is None, so the execution directly jumps to the return render(request,'sheet.html',context) statement. At this point context has NOT been assigned to so the name doesn't exist in the local scope. Hence the exception you get.

Actually, you should not use a POST request to start with - searching/filtering data is idempotent (it does not change the server's state), so you do want to use GET instead (as your form's 'method' attribute, and as the request attribute to lookup for query args). This is the official correct way (and as a side benefit it makes your search/filter results urls bookmarkables and shareables since all is in the url's querystring).

Then to keep your navigation consistent, you have to add back the search/filter arguments (here 'datetime1' and 'datetime2') to your pagination links querystrings.

Finally, your view should not depend on having either of those arguments passed in the querystring, nor assume that if any of them is set then the other is set too. IOW you want a default unfiltered queryset first, then apply relevant filtering depending on which query args were passed, then only paginate and populate your context:

posts = Post.objects.all() # default

# NB : you're not using a Django form here (you really should)
# so what you will get are raw strings values, and possibly
# invalid ones. User inputs validation and sanitization is
# hard (and boring) so better let Forms take care of it, 
# that's what they are for.
date_sel1 = request.GET.get('datetime1',None)
date_sel2 = request.GET.get('datetime2',None)

if date_sel1 and date_sel2:
    # both where passed, filter on date range
    posts = posts.filter(pub_date__range=(date_sel1,date_sel2))
elif date_sel1:
    # only first argument was passed, filter on date_gte:
    posts = posts.filter(pub_date__gte=date_sel1)
elif date_sel2:
    # only first argument was passed, filter on date_lte:
    posts = posts.filter(pub_date__lte=date_sel2)
# ok no we have our possibly filtered queryset, let's order it
# and returns the result:

# XXX unrelated but it looks like you're using a DateField 
# and a distinct TimeField. Why not use a DatetimeField ?

posts = posts.order_by("pub_date","time")

paginator = Paginator(posts,6,1)
# XXX unrelated : better naming. `paginator.page(x)` 
# returns a `Page` object so why name it "customer" ?
pagenum = request.GET.get('page')
try:
    page = paginator.page(pagenum)
except PageNotAnInteger:
    page = paginator.page(1)
except EmptyPage:
    page = paginator.page(paginator.num_pages)

# populates the context with our page object 
# AND the (possibly empty) datetimeX values
# so we can add them to pagination links
# (and eventually display them to our user)
context={'posts':page, "datetime1": date_sel1,"datetime2": date_sel2}
return render(request,'sheet.html',context)

Upvotes: 2

Related Questions