Emmet B
Emmet B

Reputation: 5531

Django: Getting the value of an ordered queryset

I have a model,

class Book(models.Model):
    name = models.CharField(max_length=300)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    rating = models.FloatField()

I am ordering Book objects dynamically based on a category, but I want to get the corresponding value as well. For example, when they are sorted I want to show corresponding prices as well.

Doing:

Book.objects.order_by('price').values()

and in template

Book: {{ book }} - Price: {{ book.value.2 }} 

works fine. However, I want to chose which field will be sortable during runtime, for example if I want to order by pages, I need to pass book.value.1. So, the view should pass the field that is sorted. Something like below would solve my problem:

{{ book.{{ sortField }} }}

Django gives an error. how can I solve this? How can I pass the field so that I can use the corresponding value?

Upvotes: 2

Views: 386

Answers (2)

Hedde van der Heide
Hedde van der Heide

Reputation: 22449

A simplified example:

template

<span>Currently ordering by {{ order_by }}</span>
<ul>
    <li><a href="?order_by=price">price</a></li>
    <li><a href="?order_by=pages">pages</a></li>
</ul>
<ul>
    {% for obj in object_list %}
        <li><a href="{{ obj.get_absolute_url }}">{{ obj.name }}</a></li>
    {% endfor %}
</ul>

views.py

class FooListView(ListView):
    allow_ordering_on = ['pk', 'pages', 'price']  # restrictions
    order_by = 'pk'

    def get(self, request, *args, **kwargs):
        order_by = request.GET.get('order_by', self.order_by)

        if order_by in self.allow_ordering_on:
            self.order_by = order_by
            self.object_list = self.model.objects.all().order_by('whatever')
            if not allow_empty and len(self.object_list) == 0:
                raise Http404(_(u"Empty list and '%(class_name)s.allow_empty' is False.")
                              % {'class_name': self.__class__.__name__})
            context = self.get_context_data(object_list=self.object_list)
            return self.render_to_response(context)

        else:
            return super(FooListView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(FooListView, self).get_context_data(**kwargs)
        context['order_by'] = self.order_by
        return context

You can override get_context_data to add a variable for marking current field ordering.

Upvotes: 2

Akshar Raaj
Akshar Raaj

Reputation: 15211

On shell:

books = Book.objects.order_by('price').values()
book = books[0]
print book['price']

So in the template you should be able to loop over books and access the fields:

{% for book in books %}    
    {{ book.price }}
{% endfor %}

Upvotes: 0

Related Questions