Question

I'm not sure what is going wrong but I'm not able to order a list generated in a CBV. I followed the instruction in the django documentation https://docs.djangoproject.com/en/1.6/topics/class-based-views/mixins/#using-singleobjectmixin-with-listview. The model is the following:

class Event(models.Model):
...
    venue = models.ForeignKey(
        'app_place.PointOfInterest',
        related_name='events',
        verbose_name=_('Event Place'),
    )
    start = models.DateTimeField(
        default=timezone.now(),
        verbose_name=_('Start date'),
    )

    def sorted_events_set(self):
        return self.event_set.order_by('start')

And the views.py contains:

class PoiDetail(SingleObjectMixin, ListView):
...
    def get_queryset(self):
        return self.object.events.all()

Everything is fine but the list in the html page is orderd by ID (reversed by the way). So I added the order_by:

return self.object.events.all().order_by('start')

But it's not working (the order remain the same). What is going on? Is this not the correct way to proceed? I also tried to add a specific ordering in the model as suggested in other questions but then I had different errors and I don't know how to write the return statement with the sorted_events_set method. Thanks for helping!

EDIT

Here is the complete views.py

class PoiDetail(SingleObjectMixin, ListView):
    template_name = 'app_place/poi.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=PointOfInterest.objects.all())
        return super(PoiDetail, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(PoiDetail, self).get_context_data(**kwargs)
        context['poi'] = self.object
        return context

    def get_queryset(self):
        return self.object.events.all().order_by('start')

And this is the template:

{% for event in poi.events.all %}
    <a href="/e20/event/{{event.id}}" class="list-group-item">
    <h4 class="list-group-item-heading">{{ event.title }}</h4>
    <p class="list-group-item-text">{{event.description}}</p>
    </a>
{% endfor %}
Was it helpful?

Solution

First of all, I wouldn't recommend mixing a SingleObjectMixin and ListView. They are written for two distinct goals and are incompatible in the way they achieve those. You can patch it up like you did, but if you're not very careful you can still run into a lot of unexpected behaviour, especially when relying on a call to super. You're actually just trying to create a detail view, so you should subclass DetailView with PointOfInterest as your model.

Now for your sorting problem: you can't pass arguments to functions in your template, so you'll have to sort the queryset in your context in the view, or create a function without any (required) arguments. I'd go with the first method, to keep logic for your view in your view code, and to prevent cluttering your model with helper methods. Either way, you'll have to keep track of which queryset you're using exactly, as sorting one queryset won't affect another queryset.

So to go with the context method:

class POIDetail(DetailView):
    model = PointOfInterest

    def get_context_data(self, **kwargs):
        context = super(POIDetail, self).get_context_data(**kwargs)
        context['sorted_event_list'] = self.object.events.order_by('start')
        return context

And in your template, iterate using {% for event in sorted_event_list %}.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top