4

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']}>

Radu Gheorghiu
  • 20,049
  • 16
  • 72
  • 107

2 Answers2

2

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 %}
     <a href="{% url search %}?page={{ results.previous_page_number }}&q_word={{ term }}">previous</a>
{% endif %}

{% if results.has_next %}
      <a href="{% url search %}?page={{ result.next_page_number }}&q_word={{ term }}">next</a>
{% endif %}
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • I'm sorry to say this but it doesn't work. It says that `local variable 'searchTerm' referenced before assignment`. And if I add a simple else statement and declare the variable `searchTerm` then I get a error for the `page` value as well saying that it is `NoneType`. I'm guessing the variables are not sent in the HTTP request, but why? The code seems ok.. – Radu Gheorghiu May 02 '12 at 10:37
  • I've used `pdb` to see what the HTTP request looks like and the GET dictionary is empty. I have no idea where the variables go to.. – Radu Gheorghiu May 02 '12 at 10:45
  • It is saying that because your logic does not account for when the person submits an empty form - I only updated the parts of your code that has to do with pagination. – Burhan Khalid May 02 '12 at 12:16
  • But why isn't the data being sent in the GET request? I understand where the logic in my view "fails", but that's because there is no data being sent.. any ideas why? – Radu Gheorghiu May 02 '12 at 12:18
  • I have just finised another post with a question regarding this issue. http://stackoverflow.com/questions/10412937/no-data-is-sent-with-get-method – Radu Gheorghiu May 02 '12 at 12:19
1

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.

dm03514
  • 54,664
  • 18
  • 108
  • 145
  • When I say describe I mean what should my `URL` look like? `url(r'^search/(what else here?)','ps.views.search')` – Radu Gheorghiu Apr 30 '12 at 14:56
  • Thanks for the hints. I'll try them out. – Radu Gheorghiu Apr 30 '12 at 14:57
  • @reos, 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\d+)/$` which would mean search would take 2 params `request` and then `page`. I don't see anything wrong with your syntax for any of the veiws you've listed. – dm03514 Apr 30 '12 at 14:58
  • I've added the `search.py` for the eventuality of other problems. – Radu Gheorghiu Apr 30 '12 at 15:09
  • Obviously I've went for the simple view and I'm trying to access the data with `request.GET['q_word'], but I get this in the `pdb` output `(Pdb) request.GET['q_word'] *** MultiValueDictKeyError: "Key 'q_word' not found in "` – Radu Gheorghiu Apr 30 '12 at 15:13
  • @reos, so your url is being hit fine!! thats good. and you are getting `page` in your GET dictionary. So now if you remove the `import pdb` it look slike verything should work fine! – dm03514 Apr 30 '12 at 15:16
  • But the search no longer works.. nothing happens. On a, hopefully short, note.. How do I access the searched word? `request.GET['q_word']` ? – Radu Gheorghiu Apr 30 '12 at 15:19
  • @reos, ooh ok i see your issue. When you are submitting the form with a search term is q_word being appended to the url? What does django runserver log say? – dm03514 Apr 30 '12 at 15:25
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/10705/discussion-between-reos-and-dm03514) – Radu Gheorghiu Apr 30 '12 at 15:27