• 일반적인 select 문
    (modelClass).objects.all()
    


  • 조건절

– filter : 값을 추가하면 and 조건으로 계속 연결

(modelClass).objects.filter(필드명1=값1, 필드명2=값2...)

– exclude : 값을 추가하면 not 조건으로 계속 연결 (modelClass).objects.exclude(필드명1=값1, 필드명2=값2…)

– or 연산

queryset = User.objects.filter(
        first_name__startswith='R'
    ) | User.objects.filter(
    last_name__startswith='D'
)
queryset
<QuerySet [<User: Ricky>, <User: Ritesh>, <User: Radha>, <User: Raghu>, <User: rishab>]>
SELECT username, first_name, last_name, email FROM auth_user WHERE first_name LIKE 'R%' OR last_name LIKE 'D%';


– 특정 값으로 시작하는 행 조회

#first_name이 'R'로 시작하는 User 모델의 행
user.objects.filter(first_name__startswith='R')


-UNION (합하려는 쿼리셋의 필드와 데이터 유형이 서로 일치할 때만 가능)

>>> q1 = User.objects.filter(id__gte=5)
>>> q1
<QuerySet [<User: Ritesh>, <User: Billy>, <User: Radha>, <User: sohan>, <User: Raghu>, <User: rishab>]>
>>> q2 = User.objects.filter(id__lte=9)
>>> q2
<QuerySet [<User: yash>, <User: John>, <User: Ricky>, <User: sharukh>, <User: Ritesh>, <User: Billy>, <User: Radha>, <User: sohan>, <User: Raghu>]>
>>> q1.union(q2)
<QuerySet [<User: yash>, <User: John>, <User: Ricky>, <User: sharukh>, <User: Ritesh>, <User: Billy>, <User: Radha>, <User: sohan>, <User: Raghu>, <User: rishab>]>
>>> q2.union(q1)
<QuerySet [<User: yash>, <User: John>, <User: Ricky>, <User: sharukh>, <User: Ritesh>, <User: Billy>, <User: Radha>, <User: sohan>, <User: Raghu>, <User: rishab>]>


  • 필요한 열만 골라 조회
>>> User.objects.filter(
    first_name__startswith='R'
).values('first_name', 'last_name')
<QuerySet [{'first_name': 'Ricky', 'last_name': 'Dayal'}, {'first_name': 'Ritesh', 'last_name': 'Deshmukh'}, {'first_name': 'Radha', 'last_name': 'George'}, {'first_name': 'Raghu', 'last_name': 'Khan'}, {'first_name': 'Rishabh', 'last_name': 'Deol'}]

only 메서드를 사용하는 경우

>> queryset = User.objects.filter(
    first_name__startswith='R'
).only("first_name", "last_name")


  • 서브쿼리 auth_user 모델과 1:1 관계로 연결된 UserParent 모델이 있는 경우
>>> from django.db.models import Subquery
>>> users = User.objects.all()
>>> UserParent.objects.filter(user_id__in=Subquery(users.values('id')))
<QuerySet [<UserParent: UserParent object (2)>, <UserParent: UserParent object (5)>, <UserParent: UserParent object (8)>]>

Category 모델의 각 행별로, 가장 선한 Hero 행

class Category(models.Model):
    name = models.CharField(max_length=100)


class Hero(models.Model):
    # ...
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

    benevolence_factor = models.PositiveSmallIntegerField(
        help_text="How benevolent this hero is?",
        default=50
    )
hero_qs = Hero.objects.filter(
    category=OuterRef("pk")
).order_by("-benevolence_factor")
Category.objects.all().annotate(
    most_benevolent_hero=Subquery(
        hero_qs.values('name')[:1]
    )
)

benevolence_factor 내림 차순으로 정렬 order_by(“-benevolence_factor”)

category의 pk와 연결 category=OuterRef(“pk)

별칭을 붙여 Category 쿼리셋 안에서 사용 most_benevolent_hero=Subquery(hero_qs.values(‘name’)[:1])


  • 필드의 값을 서로 비교하여 항목을 선택
# 이름과 성일 동일한 사용자
User.objects.filter(last_name=F("first_name"))


  • 파일이 없는 행을 구하는 방법
no_files_objects = MyModel.objects.filter(Q(file='')|Q(file=None))


  • 두 모델을 결합(JOIN)
# Using select_related
a1 = Article.objects.select_related('reporter')

#filter
a2 = Article.objects.filter(reporter_username='John')


  • 첫번째 항목, 두번째 항목, N 번째 항목

첫번째 항목 : first()

마지막 항목 : last()

N 번째 항목 : 인덱싱 연산

>>> user = User.objects.order_by('-last_login')[1] // Second Highest record w.r.t 'last_login'
>>> user.first_name
'Raghu'
>>> user = User.objects.order_by('-last_login')[2] // Third Highest record w.r.t 'last_login'
>>> user.first_name
'Sohan'


  • 특정 열의 값이 동일한 항목
>>> duplicates = User.objects.values(
    'first_name'
    ).annotate(name_count=Count('first_name')).filter(name_count__gt=1)
>>> duplicates
<QuerySet [{'first_name': 'John', 'name_count': 3}]>
# 중복 값을 가진 항목 조회
>>> records = User.objects.filter(first_name__in=[item['first_name'] for item in duplicates])
>>> print([item.id for item in records])
[2, 11, 13]


  • 고유한 필드 값을 가진 항목
# 이름이 다른 사용자와 겹치지 않는 사용자
distinct = User.objects.values(
  'first_name'
).annotate(
  name_count=Count('first_name')
).filter(name_count=1)
records = User.objects.filter(first_name__in=[item['first_name'] for item in distinct])
# 고유한 first_name을 가진 사용자별로 첫번재 사용자
User.objects.distinct("first_name").all()


  • 최근 PK 값 조회
result = (modelClass).objects.latest('pk 필드명')
result._get_pk_val()


  • Q 객체 활용법

– OR 연산

>>> from django.db.models import Q
>>> queryset = User.objects.filter(
    Q(first_name__startswith='R') | Q(last_name__startswith='D')
)
>>> queryset
<QuerySet [<User: Ricky>, <User: Ritesh>, <User: Radha>, <User: Raghu>, <User: rishab>]>

– AND 연산

>>> queryset = User.objects.filter(
    Q(first_name__startswith='R') & Q(last_name__startswith='D')
)
>>> queryset
<QuerySet [<User: Ricky>, <User: Ritesh>, <User: rishab>]>
# first_name이 R로 시작하되 last_name이 Z가 포함되지 않은 사용자
>>> queryset = User.objects.filter(
    Q(first_name__startswith='R') & ~Q(last_name__startswith='Z')
)


  • 기록된 항목의 집계 (Max, Min, Avg, Sum)
>>> from django.db.models import Avg, Max, Min, Sum, Count
>>> User.objects.all().aggregate(Avg('id'))
{'id__avg': 7.571428571428571}
>>> User.objects.all().aggregate(Max('id'))
{'id__max': 15}
>>> User.objects.all().aggregate(Min('id'))
{'id__min': 1}
>>> User.objects.all().aggregate(Sum('id'))
{'id__sum': 106}


  • 장고가 지원하지 않는 데이터 베이스 함수 활용
from django.db.models import Func, F
Hero.objects.annotate(like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')"))

Func 객체를 세개의 인자로 초기화. 첫 번째 인자는 함수에 적용할 열, 두 번째 인자는 데이터베이스에서 실행할 함수의 이름, 세 번째 인자는 함수를 실행할 SQL 질의문의 템플릿


출처

https://django-orm-cookbook-ko.readthedocs.io/en/latest