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!
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.
There are several levels for display ordered models objects in template, each one overwrite the previous level:
- (MODEL LEVEL) Meta attribute
ordering
as shows @Bithin in his answer (more on django docs)
-
(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.
- (TEMPLATE LEVEL)
regroup
template tag need to use nested in your sample (more on django docs)
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.
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!
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.
There are several levels for display ordered models objects in template, each one overwrite the previous level:
- (MODEL LEVEL) Meta attribute
ordering
as shows @Bithin in his answer (more on django docs) -
(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. - (TEMPLATE LEVEL)
regroup
template tag need to use nested in your sample (more on django docs)
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.