Django: How to write query to sort using multiple columns, display via template

Question:

I’m quite new to Django, and not too experienced with MVC, DB queries.

I have a Customer table which includes customer_name, city_name, as well as a state_name (pulled from a foreign key table). In the HTML, I’m trying to display the results in a list first sorted alphabetically by state_name, then by city_name, then by customer_name name. Like so..

ARIZONA
   PHOENIX
     AAA, Inc.
     BBB, LLC.

   SCOTTSDALE
     AAA, LLC.
     DDD, Corp.

CALIFORNIA
   ANAHEIM
     ...

My model.py is as follows:

from django.db import models

class Customer(models.Model):
    def __unicode__(self):
        return self.customer_name

    customer_name = models.CharField(max_length=60)
    city_name = models.CharField(max_length=30)
    state = models.ForeignKey('State')

class State(models.Model):
    def __unicode__(self):
         return self.state_name

    state_name = models.CharField(max_length=20)
    state_code = models.CharField(max_length=2)

In my urls.py, I have:

url("^customers/$",
    direct_to_template,
    {'template': 'pages_fixed/customers.html',
    'extra_context': {'customers': Customer.objects.all().order_by('state')}},
    name='customers'),

And in my HTML, I have a working template as:

    <div class='customers'>
        {% for customer in customers %}
            <div class='block_customer'>
                <p>{{ customer.state.state_name }}</p>
                <p>{{ customer.city_name }}</p>
                <p>{{ customer.customer_name }}</p>
            </div>
        {% endfor %}
    </div>

It’s all sort of working but obviously not sorting correctly and I’m not sure what’s the best way to design it. I tried some inner loops with the templates, was hoping the templates would let me define some sorting rules but this doesn’t seem to be supported/correct. I suspect that I need to query the data differently or pre-sort them in code ahead of time? I’m not sure if this would be done in the View (what is Django’s form of Controller?).. If anyone could point me in the right direction, that would be MUCH appreciated!

Asked By: pete

||

Answers:

You can specify the ordering inside the model,

class Customer(models.Model):

    customer_name = models.CharField(max_length=60)
    city_name = models.CharField(max_length=30)
    state = models.ForeignKey('State')

    def __unicode__(self):
        return self.customer_name

    class Meta:
           ordering = ['customer_name', 'city_name', 'state']

Hope this helps.

Answered By: Bithin

There are several levels for display ordered models objects in template, each one overwrite the previous level:

  1. (MODEL LEVEL) Meta attribute ordering as shows @Bithin in his answer (more on django docs)
  2. (VIEW LEVEL) QuerySet order_by method as you have tried in your view example, which would works
    as you want if add other fields to sort:

    Customer.objects.order_by('state', 'city_name', 'customer_name')

    (more on django docs). Note that .all() is not needed here.

  3. (TEMPLATE LEVEL) regroup template tag need to use nested in your sample (more on django docs)
Answered By: juliocesar

If you want to order by some field of the “master” model, in this case state, you must write something like this:

Customer.objects.order_by('state__state_name', 'city_name', 'customer_name')

Take a look of state__state_name, the double _ after the first state, make access to the field of that model.

Answered By: DanielB