2016-05-21 16 views
6

Sto cercando di raggruppare i record dal carattere di name campo di ciascun record e limitare gli oggetti in ogni gruppo, qui è quello che ho si avvicinò con:Django oggetto di gruppo dal primo carattere di una colonna

desired_letters = ['a','b','c',..,'z'] 
some_variable = {} 
for desired_letter in desired_letters: 
    some_variable += User.objects.all().order_by("name").filter(name__startswith=desired_letter)[:10] 

E eseguo questa query in un ciclo for e cambio desired_letter nella lettera desiderata, esiste un altro modo per ottimizzare questa soluzione e renderla una singola query anziché un ciclo for?

+0

Ok, quindi come possiamo aiutare? –

+0

@MosesKoledoye Ho bisogno di ottimizzare questo e magari renderlo una singola query usando la funzione 'values ​​()' – samix73

+0

Questo gruppo non ha senso, vero? Se stai raggruppando per la prima lettera del nome di ogni utente, riceverai solo 26 record è quello che stai cercando? – e4c5

risposta

8

Dalla commentare nel altra risposta:

mi è stato effettivamente alla ricerca di un modo per implementare Group By First Character in ORM Django

lo farei a seguire 3 passi:

  1. Annota ogni record con la prima lettera del campo name. Per questo è possibile utilizzare la funzione Substr insieme Lower

    from django.db.models.functions import Substr, Lower 
    qs = User.objects.annotate(fl_name=Lower(Substr('name', 1, 1))) 
    
  2. Avanti, raggruppare tutti i record con questa prima lettera e ottenere il numero di ID. Questo può essere fatto utilizzando annotate with values:

    # since, we annotated each record we can use the first letter for grouping, and 
    # then get the count of ids for each group 
    from django.db.models import Count 
    qs = qs.values('fl_name').annotate(cnt_users=Count('id')) 
    
  3. successivo, è possibile ordinare questo set di query con la prima lettera:

    qs = qs.order_by('fl_name') 
    

combinazione di tutte queste cose in una dichiarazione:

from django.db.models.functions import Substr, Lower 
from django.db.models import Count 

qs = User.objects \ 
     .annotate(fl_name=Lower(Substr('name', 1, 1))) \ 
     .values('fl_name') \ 
     .annotate(cnt_users=Count('id')) \ 
     .order_by('fl_name') 

Alla e e il tuo queryset sarebbe simile a questo. Nota che ho convertito il primo carattere in minuscolo durante l'annotazione. Se non avete bisogno di questo, è possibile rimuovere la funzione Lower:

[{'fl_name': 'a', 'cnt_users': 12}, 
{'fl_name': 'b', 'cnt_users': 4}, 
... 
... 
{'fl_name': 'z', 'cnt_users': 3},] 

Se avete bisogno di un dizionario di lettere e contare:

fl_count = dict(qs.values('fl_name', 'cnt_users')) 
# {'a': 12, 'b': 4, ........., 'z': 3} 
2

Il primo ordine e quindi il filtraggio sono eccessivi e invano. dovresti solo ordinare i dati che ti servono. Altrimenti si ordinano tutte le righe per nome e quindi per filtrare e affettare ciò che è necessario.

farei:

User.objects.filter(name__startswith=desired_letter).order_by("name")[:10] 

e .all() era ridondante.

+0

grazie per la risposta, che ne dici di raggruppare, c'è un altro modo di usare per il ciclo? – samix73

+0

@ samix73 puoi mostrare il tuo ciclo? – doniyor

+0

Ho modificato la domanda, in realtà stavo cercando un modo per implementare [questo] (http://stackoverflow.com/questions/666525/group-by-first-character) in django orm – samix73