2016-05-21 16 views
6

Próbuję zapisów grupowych o charakterze name polu każdego rekordu i ograniczenia pozycji w każdej grupie, tutaj jest to, co ja przyszedłem z:Django grupa obiekt pierwszym znakiem kolumny

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] 

Uruchomiłem to zapytanie w pętli for i zmieniłem desired_letter na żądaną literę, czy istnieje inny sposób optymalizacji tego rozwiązania i uczynienia go pojedynczym zapytaniem zamiast pętli for?

+0

Ok, więc w jaki sposób możemy pomóc? –

+0

@MosesKoledoye Muszę zoptymalizować to i może zrobić to za pomocą pojedynczej kwerendy używając funkcji 'values ​​()' – samix73

+0

Ta grupa nie ma sensu? Jeśli grupujesz według pierwszej litery nazwiska każdego użytkownika, dostaniesz 26 rekordów, to czego szukasz? – e4c5

Odpowiedz

8

Z komentarzem w drugiej odpowiedzi:

I faktycznie szuka sposobu, aby wdrożyć Group By First Character w django orm

Chciałbym zrobić to w 3 następujących czynności:

  1. Opisuj każdy rekord pierwszą literą pola name. W tym celu można użyć Substr funkcję wraz z Lower

    from django.db.models.functions import Substr, Lower 
    qs = User.objects.annotate(fl_name=Lower(Substr('name', 1, 1))) 
    
  2. Następnie grupa wszystkie rekordy z pierwszej litery i uzyskać liczbę identyfikatorów. Można to zrobić za pomocą 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. Następnie można zamówić queryset z pierwszego listu:

    qs = qs.order_by('fl_name') 
    

łącząc wszystkie te w jednym stwierdzeniem:

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') 

Na e nd, twój queryset wyglądałby tak. Zauważ, że podczas pisania adnotacji konwertowałem pierwszy znak na małe litery. Jeśli nie musisz, że można usunąć Lower funkcję:

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

jeśli trzeba słownika pisma i liczyć:

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

Pierwsze zamówienie, a następnie filtrowanie jest przesadą i na próżno. powinieneś tylko zamówić potrzebne dane. W przeciwnym razie zamawiasz wszystkie wiersze według nazwy , a następnie filtrowanie i cięcie według potrzeb.

zrobiłbym:

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

i .all() był zbędny.

+0

dziękuję za odpowiedź, a co z grupowaniem, czy istnieje inny sposób niż użycie pętli? – samix73

+0

@ samix73 Czy możesz pokazać swoją pętlę for? – doniyor

+0

Edytowałem pytanie, faktycznie szukałem sposobu na wdrożenie [this] (http://stackoverflow.com/questions/666525/group-by-first-character) w django orm – samix73