let's assume I have a django model like this:
class Event(CommonSettings) :
author = models.ForeignKey(User)
timestamp = models.DateTimeField(auto_now_add=True)
event_type = models.ForeignKey(Event_Type, verbose_name="Event type")
text_field = models.TextField()
flag_box = models.BooleanField()
time = models.TimeField()
date = models.DateField()
project = models.ForeignKey(Project)
now, by default, I have a view where I sort all events by time & date:
event_list = Event.objects.filter().order_by('-date', '-time')
however, maybe the user wants to sort the events by time only, or by the date, or maybe in ascending order instead of descending. I know that I can create urlpatterns that match all these cases and then pass on the these options to my view, however I feel like I'm reinventing the wheel here. the django admin site can do all of this out of the box.
So here's my question: is there a clever, easy way of getting this done in a generic way, or do I have to hard code this for my models / views / templates?
and yes, I did find solutions like this (https://gist.github.com/386835) but this means you use three different projects to achi开发者_运维技巧eve one thing - this seems to be a too complicated solution for such a simple thing.
EDIT1: how do I have to change the template so that I can combine multiple filters? Right now I have
<a href="?sort=desc">Desc</a>
<a href="?sort=asc">Asc</a>
but I want to allow the user to also change number of entries that get displayed. So I have:
<a href="?order_by=date">order by date</a>
<a href="?order_by=name">order by name</a>
This works all fine, but if I click on 'order by date' and then I click on 'Asc', then my previously selected order disappears. That's not what I want. I want the user to be able to combine some options but not others.
EDIT2: unfortunately your solution doesn't work with
from django.views.generic.list_detail import object_list
and it's
paginate_by
option.
I tried:
<a href="?sort={{sort_dir}}?page={{ page_obj.previous_page_number }}" class="prev">prev</a>
<a href="?sort={{sort_dir}}?page={{ page_obj.next_page_number }}" class="next">{% trans "next" %}</a>
but the links then just don't work (nothing happens). maybe you need to do something special with "object_list"?
I don't think it's as much work as you're making it out to be - you can use variables instead of explicitly creating separate url patterns. If you look at how the django admin handles it, they tack on request variables to the url like ?ot=asc&o=2
This corresponds to sort in ascending order in by the 2nd column. Of course, if you designing a particular page, you might as well use more readable naming. So instead of numbering the categories, i'd do ?sort=desc&order_by=date
and then put a regular expression in the view to match the different possibilities. Something like:
order = re.match(r"(?:date|time|name)$", request.GET['order_by'])
if request.GET['sort'] == 'desc':
order = '-' + order
results = Event.objects.filter().order_by(order)
You could instead use the regexp as a url pattern matcher as you suggested, but it's more common to let the url itself represent which part of the site you're at (i.e. website.com/events/
) and the url request variables represent how that content is being displayed (i.e. ?order_by=date&sort=desc
).
Hope that helps!
EDIT: For the second part of your question, use Django's templating system (which reads variables) instead of just html. There are several ways I can think of to do this, depending on personal preference and how exactly you want the UI to function (i.e. page loads with new variables anytime the user chooses a filter, or the user chooses all filter options in a form and then submits it so the page only has to reload once, etc). In this case, you could just do:
<a href="?sort_by=asc&order_by={{order}}">Ascending</a>
<a href="?sort_by=desc&order_by={{order}}">Descending</a>
<a href="?sort_by={{sort}}&order_by=name">Name</a>
<a href="?sort_by={{sort}}&order_by=date">Date</a>
Then in the view make sure your render_to_response arguments include a dictionary that looks like: {'order': request.GET['order_by'], 'sort': request.GET['sort_by'], }
Unfortunately, (and someone please correct me if I'm wrong) I don't think there's a template tag to generate a url with request.GET parameters - the url tag {% url name_of_view order_by=name sort_by=desc %}
would generate "path/to/name_of_view/name/desc/", but I don't think there's a tag to generate "path/to/name_of_view?order_by=name&sort_by=desc". It would be pretty easy to write a custom tag for this though (I wouldn't be surprised if there's already one on django-snippets or something, although I just did a quick google search and didn't find anything).
精彩评论