query - get model django
En Django, ¿cómo puedo ordenar por un CharField de opción múltiple en orden arbitrario y no alfabético? (5)
Debe configurar su campo de size
con tuplas de opciones ordenadas de la forma que desee. En su models.py
, tendría algo como:
from django.db import models
SHIRT_SIZE_CHOICES = (
(u"0", u"small"),
(u"1", u"medium"),
(u"2", u"large"),
(u"3", u"xlarge"))
class Shirt(models.Model):
...
size = models.CharField(max_length=2, choices=SHIRT_SIZE_CHOICES)
Entonces order_by
los clasificará como lo desea.
Imagine un modelo de Shirts
con un size
CharField, con valores limitados a un pequeño número de opciones, por ejemplo, ''pequeño'', ''medio'', ''grande'', ''xlarge'', etc.
Para agrupar las camisetas por tamaño, harías:
Shirts.objects.order_by(''size'')
Pero Django (naturalmente) ordenará los grupos alfabéticamente, es decir, "grande", luego "mediano", luego "pequeño" y luego "xlarge". Lo que quiero es tener ''pequeño'' antes de ''medio'' antes de ''grande'', etc.
Es decir, lo que naturalmente quiero hacer es algo así como el siguiente pseudocódigo:
size_order = {''small'': 1, ''medium'': 2, ''large'': 3, ''xlarge'': 4}
Shirts.objects.order_by(''size_order[size]'')
¿Cuál es la mejor manera de lograr esto?
EDITAR: Vea mis comentarios a las respuestas a continuación para obtener ideas sobre diversos enfoques sugeridos. He tropezado con un enfoque personalizado de Manager / QuerySet usando la sintaxis SQL ORDER BY CASE que estoy investigando.
Parece que no desea codificar las opciones posibles (porque usó un charfield), pero al mismo tiempo dice que hay pocas opciones.
Si está contento con codificar las opciones, puede cambiar a un campo entero en su lugar:
class Shirt(models.Model):
SIZE_CHOICES = (
(1, u''small''),
(2, u''medium''),
(3, u''large''),
(4, u''x-large''),
(5, u''xx-large''),
)
size = models.IntegerField(choices = SIZE_CHOICES)
Si no desea codificar las opciones de tamaño, probablemente desee mover los tamaños disponibles a un modelo diferente y hacer referencia a él como una clave externa de su modelo de Camisa. Para hacerlo arbitrariamente ordenable necesitaría un índice de algún tipo que no sea la clave principal que puede ordenar. Tal vez algo como esto:
class Size(models.Model):
sortorder = models.IntegerField()
name = models.CharField()
class Meta:
ordering = [''sortorder'']
Si no desea almacenar los valores del campo como enteros, el método integrado en order_by () no podrá manejar su caso personalizado. Tendrá que crear una función propia para ordenar los datos una vez que los haya recuperado.
Y para hacer eso, por supuesto, la mejor manera sería mapear sus valores arbitrarios a enteros en el orden respectivo y luego ordenar por esa disposición :).
Sin escribir una función de clasificación personalizada, simplemente inserte un campo de order
en el modelo.
class Shirt(models.Model):
...
order = models.IntegerField(default=0)
class Meta:
ordering = (''order'',)
Shirt.objects.filter(name=''Awesome Shirt'')
O, más apropiadamente, cree un nuevo modelo llamado Size
.
Descubrí lo más parecido a lo que estoy buscando, que es utilizar el método QuerySet.extra()
para aprovechar la sintaxis CASE WHEN / THEN de SQL, que Django no admite directamente:
CASE_SQL = ''(case when size="small" then 1 when size="medium" then 2 when size="large" then 3 when size="xlarge" then 4 end)''
Shirt.objects.extra(select={''shirt_order'': CASE_SQL}, order_by=[''shirt_order''])
Esto puede parecer excesivo y / o sucio dado mi ejemplo (artificial), ¡pero es el truco que estaba buscando! Gracias a todos por los otros enfoques perfectamente válidos para este problema, que de alguna manera indirectamente me impulsó a descubrir este enfoque.
PD. Es tentador crear un modelo personalizado de Administrador / QuerySet que proporciona una interfaz Django más nativa para este tipo de pedidos personalizados a través de la sintaxis CASE WHEN / THEN de SQL, ¡pero lo dejaré como una tarea para mí en otro momento!
NOTA: La sintaxis para CASE WHEN / THEN es específica de la base de datos. La sintaxis anterior es para SQLite. Para PostgreSQL, omita los paréntesis y use comillas simples escapadas en lugar de comillas dobles.