Ssul's Blog

django orm 주요 명령어 정리(exclude, values, annotate, order_by, date__range) 본문

dev/까먹지마

django orm 주요 명령어 정리(exclude, values, annotate, order_by, date__range)

Ssul 2023. 1. 11. 21:46

매번 사용할때마다 구글찾아 검색하는 쿼리셋 명령어. 오늘은 자주 찾았던 명령어들 몇개를 정리해보고자 한다.

 

0. 우선 모델 정리

습관을 인증하는 서비스로,

User, Habit, HabitLog 3개의 모델이 있다

User는 사용자 정보가 있으며,

Habit은 습관을 생성한 유저정보를 외래키로 참조하고, 습관명, 해당월 등으로 구성

HabitLog는 인증한 습관을 외래키로 참조하고, 날짜와 사진으로 구성된다

 

목표는 월별, 전체기간별 습관인증 횟수를 카운트하는 api를 생성하는 것이다.

#models.py

#사용자
class User(BaseUser, SoftDeleteModelMixin):
	name = models.CharField(_("name"), max_length=150)
    image = models.FileField(_("profile image"), null=True, blank=True)
    nick = models.CharField(_("nick"), max_length=150, blank=True, default="")
    phone = models.CharField(_("phone"), max_length=25)
    #생략

# 월별 습관
class MakingHabit(SoftDeleteModelMixin, TimestampMixin):
    owner = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="making_habits"
    )
    habitcategory = models.CharField(
        _("habitcategory"), choices=HabitCategory.choices, max_length=15, null=True, blank=True
    )
    title = models.CharField(_("title"), max_length=255)
    started_at = models.DateTimeField(_("started_at"))
    ended_at = models.DateTimeField(_("ended_at"))

# 습관 기록
class HabitLog(SoftDeleteModelMixin, TimestampMixin):
    habit = models.ForeignKey(
        MakingHabit, on_delete=models.CASCADE, related_name="logs"
    )
    date = models.DateField(default=date.today)
    image = models.FileField(_("evidence image"), null=True, blank=True)

 

1. 특정조건 제외해기 exclude

습관인증 db속에 테스트 했던 개발자의 데이터가 함께 들어있음. 그에 따라 인증 순위1위에 개발자가 있음. 개발자의 인증데이터를 뺀 쿼리셋이 필요

qs = HabitLog.objects.exclude(habit__owner__nick='개발자')
>>> 습관인증 데이터 중 유저의 닉네임이 '개발자'인 데이터는 제외

qs = qs.exclude(habit__owner__nick='운영자')
#운영자도 제외하고 싶다면, 쿼리셋을 받아서 또 exclude

*하나더 알아두면 좋은 것은 외래키로 참조된 테이블간의 참조는 __를 붙이면 참조가능

habitlog(habit) - habit(owner) - User로 참조하고 있으므로, User의 nick을 참조하려면 habit__owner__nick으로 참조가능

 

 

2. 원하는데로 컬럼 뽑아서 테이블 구성 values()

현재 Habitlog 테이블 구성은

HabitLog.objects.all()
>>> habitlog_id | habit(인증할 습관) | 인증일자 | 인증이미지 4개 컬럼이 있는 테이블

연결된 테이블들도 활용하여 내가 원하는 형태의 데이터 테이블(쿼리셋)을 구성가능

나는 순위별로 닉네임, 프로필이미지, 인증횟수를 내림차순으로 출력할 것이기 때문에 3개만 가져오면 된다.

이럴때 values를 사용한다.

qs = qs.values('habit__owner__nick', 'habit__owner__image','date')
#여기서도 HabitLog에 있지 않고, 외래키로 연결된 유저의 닉네임, 프로필 이미지도 가져 올수 있다 __로

>>> 습관인증한 데이터 모두를 출력
>>> 인증한 User의 닉네임 | 인증한 User의 프로필이미지 | 인증일자
>>> 형태로 쿼리셋이 만들어짐

 

3. 복잡한 컬럼명 변경(api서버가 response할때 원하는 변수명으로 dict구성) annotate() #1

사용자나 프론트에서 굳이 백앤드의 모델구성을 알 필요가 없기 때문에, 간단하게 변경

habit__owner__nick > nick

habit__owner__image > image

qs = qs.annotate(nick=F("habit__owner__nick"), pimage=F("habit__owner__image")).values('nick', 'pimage')
>>> nick | pimage 로 구성된 qs이 생성

 

4. 그룹별로 갯수 카운트(특정 유저가 인증한 횟수 카운트) annotage() #2

우리 서비스의 경우, 하루 한번 인증이 가능하기 때문에 인증한 date를 카운트 하면 된다.

qs = qs.annotate(nick=F("habit__owner__nick"), pimage=F("habit__owner__image")).filter(date__range=[month_start, today]).values('nick', 'pimage').order_by('nick').annotate(point=Count('date'))
>>> nick, pimage, date에서
>>> nick, pimage별로 인증한 date를 카운트해서 point 컬럼으로 셋팅
>>> nick | 프로필이미지 | 인증횟수(point) 이렇게 3개 컬럼의 테이블 출력

 

5. 큰 숫자부터 앞에 오게 정렬(포인트가 큰 순서로 위에 오게 > 내림차순) order_by()
qs = qs.order_by('-point')[:15]
>>> 포인트가 높은 사람이 위로,
>>> 그중 탑15명만 추리기 [:15]

 

6. 특정기간 데이터만 추출

우리 서비스의 경우 매달 인증순위를 출력해야 하기 때문에

오늘 날짜를 기반으로 이번달 1일부터 - 지금까지 데이터만 뽑아오기!

	# 오늘 날짜 구하기
	today = timezone.now().date()
        # 이번달 1일을 month_start에 저장
        month_start = today.replace(day=1)

		#아까와 동일. 개발자, 운영자 데이터 미포함
        qs = HabitLog.objects.exclude(habit__owner__nick='개발자')
        qs = qs.exclude(habit__owner__nick='운영자')

        # filter(date__range=[month_start, today])를 활용하여 이번달 데이터만 추출
        qs = qs.annotate(nick=F("habit__owner__nick"), pimage=F("habit__owner__image")).filter(date__range=[month_start, today]).values('nick', 'pimage').order_by('nick').annotate(point=Count('date'))
        qs = qs.order_by('-point')[:15]

        return Response(qs)