오늘의 포스팅은 간단하게 아래 글의 번역본 정도가 될 것 같습니다.
www.dev2qa.com/what-does-double-underscore-__-means-in-django-model-queryset-objects-filter-method/
장고를 하시는 분들은 이미 아주 자연스럽게 쓰는 것 같은데 모르고 있었다는게 너무나 뼈아프네요.
예제 자체는 오라클의 연습용 데이블인 emp 테이블을 사용하는것 같습니다.
이전 포스트가 있는 모양인데, 테이블의 내부 구조가 궁금하시면 아래 링크를 참고하시는 것을 추천합니다.
www.dev2qa.com/django-simple-crud-operation-example/
-------------------------
일단 아래의 한줄 코드를 실행해본다고 생각합시다.
Department.objects.filter(dept_desc__contains='dev2qa')
<QuerySet [<Department: Development,Develop dev2qa.com website use Django>]>
필터 함수의 매개변수인 dept_desc__contains='dev2qa' 가 무슨 뜻인지는 직관적으로 이해할 수 있습니다.
쿼리셋의 결과셋에서, dept_desc column이 'dev2qa'를 반드시 포함하고 있어야 한다는 뜻이겠죠.
1. Field Lookups.(필드 조회)
장고에서 위에 해당하는 부분을 field lookups 매개변수라고 부릅니다.
매개변수의 형식은 "field명__조회방법=value" 로 정의되어 있습니다.
위 예제에서는 dept_desc가 필드명을, contains가 조회방법을 지정하게 됩니다.
위 코드가 생성하는 SQL은 대략적으로 아래와 같은 모습을 가지게 됩니다.
SELECT "dept_emp_department"."id", "dept_emp_department"."dept_name", "dept_emp_department"."dept_desc" FROM "dept_emp_department" WHERE "dept_emp_department"."dept_desc" LIKE %dev2qa% ESCAPE '\'
2. Built-in Field Lookup Type
contains와 같은 다양한 조회 방법을 지정할 수 있다면, 당연히 그 조회 방법을 커스텀하는 방법도 있을 겁니다.
장고는 대체로 그러한 방법으로 만들어져 있으니까요.
어쨌거나, 그러한 조회 방법은 이미 구현되어 있는 것이 많습니다.
그 중 몇가지가 해당 게시글에 소개되어 있습니다.
2.1 exact
정확히 일치하는 조건일때 결과를 반환해주는 옵션입니다만,
필터의 기본 옵션과 똑같은 내용입니다.
dept = Department.objects.filter(dept_name__exact='Develop')
dept = Department.objects.filter(dept_name='Develop')
위 2개 코드의 동작이 다르지 않습니다.
2.2. iexact
exact옵션과 거의 비슷하지만, 영어의 대소문자를 무시하고 매칭을 시켜주게 됩니다.
None인경우 null과 대응됩니다.
dept = Department.objects.filter(dept_name__iexact='Develop')
dept = Department.objects.filter(dept_name_iexact=None)
2.3 contains
정확히 포함하는 조건일때 매칭을 시켜줍니다.
dept = Department.objects.filter(dept_name__contains='Develop')
2.4 icontains
마찬가지로 contains의 조건에서 대소문자를 무시하고 매칭을 시켜주게 됩니다.
dept = Department.objects.filter(dept_name__icontains='Develop')
2.5 in
파이썬의 in 연산자에 맞는 동작을 합니다.
list나 tuple인 경우에는 해당 element를 포함하고 있는지 검사하며,
string인 경우 포함 여부를 검사하게 됩니다.
Department.objects.filter(id__in=[1,3,5])
Department.objects.filter(dept_name__in='Dev')
거기에 추가로 쿼리셋을 필터 in 검색조건의 value로 사용할 수 있습니다.
dept_qs = Department.objects.filter(dept_name__exact='Develop')
emp_qs = Employee.objects.filter(dept__in=dept_qs)
2.6 gt, gte, lt, lte
- gt : > , greater than.
- gte : >= , greater than or equal.
- lt : < , less than.
- lte : <=, less than or equal
간단한 대소비교 조건을 걸 수도 있습니다.
equal인 경우는 당연히 조건을 걸지 않으면 됩니다.
2.7 startswith, istartsawith
해당 문자열로 시작하는지 여부를 검사할 수 있습니다.
i가 붙은 istartswith은 위 다른 조건들과 마찬가지로 대소문자를 무시합니다.
Department.objects.filter(dept_name__startswith='D')
Department.objects.filter(dept_name__istartswith='D')
2.8 endswith, iendswith
해당 문자열로 끝나는지 여부를 검사할 수 있습니다.
i가 붙은 iendswith은 위 다른 조건들과 마찬가지로 대소문자를 무시합니다.
Department.objects.filter(dept_name__endswith='p')
Department.objects.filter(dept_name__iendswith='e')
2.9 range
범위를 검사하는 조건입니다.
value를 튜플 형태로 입력 받습니다.
import datetime
start_date = datetime.date(2018,1,1)
end_date = datetime.date(2020,1,1)
Employee.objects.filter(emp_onboard_date__range=(start_date, end_date))
2.10 date
정확한 날짜를 검사하는 조건입니다.
value로 datetime.date 객체를 넘겨주어야만 합니다.
compare_date = datetime.date(2018,1,1)
Employee.objects.filter(emp_onboard_date__date=compare_date)
2.11 year, month, day, week
년도, 월, 날짜, 주차 등을 필터링 할 수 있게 합니다.
여기서 특별한 기능이 소개 되는데, 언더스코어 2개 이후 gt 등의 조건을 추가할 수 있다는 점입니다.
Employee.objects.filter(emp_onboard_date__year=2019)
Employee.objects.filter(emp_onboard_date__year__gt=2019)
Employee.objects.filter(emp_onboard_date__month=2)
Employee.objects.filter(emp_onboard_date__month__gt=2)
Employee.objects.filter(emp_onboard_date__day=21)
Employee.objects.filter(emp_onboard_date__day__gt=21)
Employee.objects.filter(emp_onboard_date__week=8)
당연히 더 많은 field lookups의 검색조건들이 있습니다.
docs.djangoproject.com/en/dev/ref/models/querysets/#field-lookups
위 주소로 접속하여 더 많은 조건을 알아볼 수 있습니다.
3. 외래키 모델 속성의 참조
장고에는 django.contrib.auth라는 강력한 인증 기능이 있습니다.
contrib이라는 이름에서 유추한 바로는 서드파티 패키지인 모양이지만 안쓰는 걸 본적이 없습니다.
로그인과 관련된 이 기능에 __를 엮어 외래키 참조를 통해서 유저명으로 검색을 진행할 수 있습니다.
from django.contrib.auth.models import User
class Employee(models.Model):
......
user = models.ForeignKey(User, on_delete=models.CASCADE,)
......
Employee.objects.filter(user__username = 'tom')
다른 종류의 외래키 참조 속성도 같은 맥락에서 검색이 가능합니다.
오늘 제가 이 글을 적게 된 계기가 된 taggit 라이브러리의
TaggableManager 역시 외래키 필드인 Foreignkey와 같은 보모인 RelatedObject를 상속합니다.
그 결과,
Post.objects.filter(tags__name=self.kwargs.get("tag"))
위와 같은 코드가 동작을 하게 되는 것이죠.
'Django and BackEnd' 카테고리의 다른 글
HTTP란? (0) | 2021.05.08 |
---|---|
Postgresql 재설치 과정 (0) | 2021.04.27 |