2009-05-19 18 views
24

Come si definisce un ordine specifico in Django QuerySet s?Ordine personalizzato in Django

In particolare, se ho un QuerySet così: ['a10', 'a1', 'a2'].

L'ordine normale (utilizzando Whatever.objects.order_by('someField')) mi darà ['a1', 'a10', 'a2'], mentre sto cercando: ['a1', 'a2', 'a10'].

Qual è il modo corretto di definire la mia tecnica di ordinazione?

risposta

39

Per quanto ne so, non c'è modo di specificare l'ordinamento lato database in questo modo in quanto sarebbe troppo specifico per il back-end. Si potrebbe desiderare di ricorrere a buon Python smistamento vecchio stile:

class Foo(models.Model): 
    name = models.CharField(max_length=128) 

Foo.objects.create(name='a10') 
Foo.objects.create(name='a1') 
Foo.objects.create(name='a2') 

ordered = sorted(Foo.objects.all(), key=lambda n: (n[0], int(n[1:]))) 
print ordered # yields a1, a2, 10 

Se vi trovate a dover questo tipo di ordinamento di un sacco, mi consiglia di fare una sottoclasse personalizzata models.Manager per il modello che esegue l'ordine. Qualcosa di simile:

class FooManager(models.Manager): 
    def in_a_number_order(self, *args, **kwargs): 
     qs = self.get_query_set().filter(*args, **kwargs) 
     return sorted(qs, key=lambda n: (n[0], int(n[1:]))) 

class Foo(models.Model): 
    ... as before ... 
    objects = FooManager() 

print Foo.objects.in_a_number_order() 
print Foo.objects.in_a_number_order(id__in=[5, 4, 3]) # or any filtering expression 
+0

Spot on! Risposta meravigliosa, grazie! –

+2

Viene visualizzato questo errore durante il tentativo di questo metodo:: \t L'oggetto 'Modello' non è indicizzabile – ninja123

+0

Does 'sorted' restituisce un set di query? Dato che è passato un queryset, lo penserei, ma penso che potrebbe anche essere convertito in un elenco o qualcosa internamente per l'ordinamento, quindi * che * viene restituito. –

0

Dipende da dove si desidera utilizzarlo.

Se si desidera utilizzarlo nei propri modelli, suggerirei di scrivere un modello-tag, che farà l'ordine per voi In esso, è possibile utilizzare qualsiasi algoritmo di ordinamento che si desidera utilizzare.

in Admin Io ordinamento personalizzato estendendo i modelli per le mie esigenze e il caricamento di un modello-tag come descritto sopra

25

@ risposta di Jarret (fare il tipo in Python) funziona alla grande per i casi semplici. Non appena si dispone di una tabella di grandi dimensioni e si desidera, ad esempio, tirare solo la prima pagina di risultati ordinati in un determinato modo, questo approccio si interrompe (è necessario estrarre ogni singola riga dal database prima di poter eseguire l'ordinamento). A questo punto vorrei esaminare l'aggiunta di un campo di "ordinamento" denormalizzato che si popola dal campo "nome" al momento del salvataggio, che è possibile ordinare a livello di DB nel solito modo.

+2

+1 per affrontare i problemi relativi alle prestazioni; infatti, il tuo suggerimento è quello che abbiamo usato su alcuni dei nostri dati che vengono utilizzati per i report, in un ambiente agnostico DB e abbiamo decine di milioni di righe, quindi posso garantire che funzioni bene . –

0

Se si dispone di set di dati più grandi e di utilizzare in aggiunta un backend SOLR (ad esempio con pagliaio):

Utilizzare solr.ICUCollationField con l'opzione numeric=true come tipo per i campi di ordinamento. Questo ordinerà secondo la lingua e se i numeri sono presenti ordinerà la parte numerica in base a regole numeriche invece di ordinamento stringa.

See: https://cwiki.apache.org/confluence/display/solr/Language+Analysis#LanguageAnalysis-UnicodeCollation http://www.solr-start.com/javadoc/solr-lucene/org/apache/solr/schema/ICUCollationField.html