views:

36

answers:

3

Hi. I'm having some trouble with the django generic object_list function's pagination not really being "smart" enough to compensate my daftness.

I'm trying to do a url for listing with optional arguments for page number and category. The url in urls.py looks like this:

url(r'^all/(?:(?P<category>[-\w]+)/page-(?P<urlpage>\d+))?/$', views.listing, ),

The category and urlpage arguments are optional beacuse of the extra "(?: )?" around them and that works nicely. views.listing is a wrapper function looking like this( i don't think this is where my problem occurs):

def listing(request,category="a-z",urlpage="1"):
extra_context_dict={}
if category=="a-z":
    catqueryset=models.UserProfile.objects.all().order_by('user__username')
elif category=="z-a":
    catqueryset=models.UserProfile.objects.all().order_by(-'user__username')
else:
    extra_context_dict['error_message']='Unfortunately a sorting error occurred, content is listed in alphabetical order'
    catqueryset=models.UserProfile.objects.all().order_by('user__username')
return object_list(
                    request,
                    queryset=catqueryset,
                    template_name='userlist.html',
                    page=urlpage,
                    paginate_by=10,
                    extra_context=extra_context_dict,
                    )

In my template userlist.html I have links looking like this (This is where I think the real problem lies):

{%if has_next%}
  <a href=page-{{next}}>Next Page> ({{next}})</a>
{%else%}

Instead of replacing the page argument in my url the link adds another page argument to the url. The urls ends up looking like this "/all/a-z/page-1/page-2/

It's not really surprising that this is what happens, but not having page as an optional argument actually works and Django replaces the old page-part of the url.

I would prefer this DRYer (atleast I think so) solution, but can't seem to get it working. Any tips how this could be solved with better urls.py or template tags would be very appreciated.

(also please excuse non-native english and on the fly translated code. Any feedback as to if this is a good or unwarranted Stack-overflow question is also gladly taken)

A: 

You're using relative URLs here - so it's not really anything to do with Django. You could replace your link with:

<a href="/all/a-z/page-{{ next }}">Next Page> ({{ next }})</a>

and all would be well, except for the fact that you'd have a brittle link in your template, which would break as soon as you changed your urls.py, and it wouldn't work unless category happened to be a-z.

Instead, use Django's built-in url tag.

<a href="{% url views.listing category next %}">Next Page> ({{ next }})</a>

To make that work, you'll have to pass your category into the extra_context_dict, which you create on the first line of your view code:

extra_context_dict = { 'category': category }
Dominic Rodger
Although all given solutions will work(thank you all), your's did not only solve my problem but also gave me a much better way to use django in general.This seems like really loose coupling which my monkey-patch of a project really needs. Thank you Dominic! BTW. I am using named urls instead of named views, any reason to why this seems so unpopular among django developers? EDIT: too slow to edit the first one :(
Tobias
@Tobias - glad I could help - thanks! I'm not sure why (or indeed whether) named URLs are unpopular amongst Django developers - I use named URLs all the time. Maybe ask a separate question about that (and include evidence that they are unpopular!).
Dominic Rodger
A: 

Is /all/a-z/page-1/page-2/ what appears in the source or where the link takes you to? My guess is that the string "page-2" is appended by the browser to the current URL. You should start with a URL with / in order to state a full path.

You should probably add the category into the extra_context and do:

 <a href="/all/{{category}}/page-{{next}}">next page ({{next}})</a>
OmerGertel
A: 

"Instead of replacing the page argument in my url the link adds another page argument to the url. The urls ends up looking like this "/all/a-z/page-1/page-2/"

that is because

'<a href=page-{{next}}>Next Page> ({{next}})</a>'

links to the page relative to the current url and the current url is already having /page-1/ in it.

i'm not sure how, not having page as an optional argument actually works and Django replaces the old page-part of the url

one thing i suggest is instead of defining relative url define absolute url

'<a href="/<other-part-of-url>/page-{{ next }}">Next Page> ({{ next }})</a>'
Ashok