Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?
Search
AhnSeongHyun
August 15, 2023
Programming
0
220
Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?
AhnSeongHyun
August 15, 2023
Tweet
Share
More Decks by AhnSeongHyun
See All by AhnSeongHyun
개발자 커리어 : 두려움이 이끄는 대로
ahnseonghyun
0
1.6k
개발자는 어떤 일을 하는 걸까?
ahnseonghyun
0
430
SQLAlchemy CustomTypes
ahnseonghyun
0
900
5번째 회사 그리고 레이니스트
ahnseonghyun
0
210
리부트 : 경력자에게도 수습이 필요한 순간
ahnseonghyun
0
2.3k
MQTT 를 이용한 주문 시스템 개선
ahnseonghyun
0
1.1k
CNN MNIST Tutorial
ahnseonghyun
0
79
github:유용한 기능들
ahnseonghyun
0
1.7k
카피캣으로 시작하는 오픈소스
ahnseonghyun
0
1.4k
Other Decks in Programming
See All in Programming
Flatt Security XSS Challenge 解答・解説
flatt_security
0
790
Alba: Why, How and What's So Interesting
okuramasafumi
0
230
.NETでOBS Studio操作してみたけど…… / Operating OBS Studio by .NET
skasweb
0
130
선언형 UI에서의 상태관리
l2hyunwoo
0
270
個人アプリを2年ぶりにアプデしたから褒めて / I just updated my personal app, praise me!
lovee
0
250
盆栽転じて家具となる / Bonsai and Furnitures
aereal
0
2.1k
HTML/CSS超絶浅い説明
yuki0329
0
200
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
2.3k
PicoRubyと暮らす、シェアハウスハック
ryosk7
0
240
“あなた” の開発を支援する AI エージェント Bedrock Engineer / introducing-bedrock-engineer
gawa
9
1k
為你自己學 Python
eddie
0
530
GitHub CopilotでTypeScriptの コード生成するワザップ
starfish719
28
6.1k
Featured
See All Featured
Code Reviewing Like a Champion
maltzj
521
39k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
39
1.9k
Raft: Consensus for Rubyists
vanstee
137
6.7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
590
Statistics for Hackers
jakevdp
797
220k
Fireside Chat
paigeccino
34
3.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Unsuck your backbone
ammeep
669
57k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
How to train your dragon (web standard)
notwaldorf
89
5.8k
StorybookのUI Testing Handbookを読んだ
zakiyama
28
5.4k
Transcript
v Django ORM에서는 어떻게 SQL where절 조건 순서를 고정할 수
있을까? 안성현
v 목차 Trigger Django ORM 이 SQL이 되기까지
History 결론
발표자 소개 안성현 @sh84ahn 페이히어 CTO (2020~) 뱅크샐러드
송금 테크리드 백엔드 개발자, 글쓰기 ash84.io
Trigger Django ORM에서 SQL Where절 조건의 순서를 고정하고 싶은데
어떻게 어떻게 찾은 방법..
Trigger Q객체를 쓰면 순서가 바뀌지 않는다는 제보 사내 블로그를
쓰기로 했지만 블로그는 쓰지않고…. 😇 파이콘 발표로 이어지는데…
ORM에서 어떻게 where절의 순서를 고정할까? where절의 순서를 고정할 필요는 없다.
그러나, 당연히 .filter(a=a, b=b) 로 하면 where a=’a’ and b=’b’ 로 SQL을 생성하지 않을까? 작성한 순서대로 출력하지 않으면, Django ORM은 어떤 기준으로 순서를 변경할까? 🧐 Django Official Site에서 해당 내용을 찾지 못함
오늘의 대상 ORM
기대했던 SQL 적은 순서대로 나오겠지?
실제 SQL 달라진 순서, 뭐가 문제일까?
filter chaining 하나의 필터 여러조건를 filter chaining으로 구성 가능
filter chaining SQL 원하는 순서대로 출력
Q를 사용하면 고정? filter chaining 대신에 Q를 이용해서 다르게 표현
가능
Q를 사용하면 고정? Q를 사용하면 순서를 고정이 된다?!! 😇
왜 다를까?
Django ORM 이 SQL이 되기까지 - filter 와 query에
대해서
filter를 알아보자
QuerySet.filter() 함수 기본적인 역할은 새로운 QuerySet 인스턴스 생성 반환
combined_queries가 있으면 에러 발생
filter() 함수 내 combined_quires 예제 django.db.utils.NotSupportedError: Calling QuerySet.filter() after
union() is not supported. union, difference, intersection 같은 함수 이후에 filter 사용시 에러 발생
QuerySet._filter_or_exclude() QuerySet의 clone을 만들어서 반환하는 부분
QuerySet._chain()
QuerySet._chain()
QuerySet._filter_or_exclude_inplace negate : 부정 여부 negate 여부에 따라 ~Q
또는 Q 객체를 생성 Query의 add_q() 함수 호출
negate 가 True인 케이스 False False True
QuerySet._filter_or_exclude_inplace args:() kwargs:{'seller_id': 1, 'cooking_day__gte': '2021-08-01', 'status': 'ORDERED'} filter
함수에서 전달한 조건들이 kwargs를 통해서 Q까지 전달 filter 함수는 내부적으로 Q객체를 만들고 _query 에 추가
Q 클래스 결정적으로 조건의 순서가 바뀌는 부분
Q 클래스 생성자에서 kwargs에 대한 오름차순 정렬 진행 kwargs.items:dict_items([
('seller_id', 1), ('cooking_day__gte', '2021-08-01'), ('status', 'ORDERED') ]) sorted:[ ('cooking_day__gte', '2021-08-01'), ('seller_id', 1), ('status', 'ORDERED') ]
Query.add_q clause: (AND: <django.db.models.lookups.GreaterThanOrEqual object at 0x125039a00>, <django.db.models.fields.related_lookups.RelatedExact object at
0x121ebe0a0>, <django.db.models.lookups.Exact object at 0x125010670>)
Query.add_q self.where: (AND: <django.db.models.lookups.GreaterThanOrEqual object at 0x16afe5dc0>, <django.db.models.fields.related_lookups.RelatedExact object at
0x16afe5ee0>, <django.db.models.lookups.Exact object at 0x16b001070>)
QuerySet에 대한 복사본을 생성 반환하는 역할 해당 복사본에 filter로 전달된
조건들(kwargs)을 Q객체로 생성됨 생성 시점에 조건들에 대해서 정렬(sorted) 수행 해당 복사본의 _query에 생성한 Q객체를 추가 filter 정리
.filter(a=a, b=b) vs. .filter(a=a).filter(b=b) filter() 함수를 호출하면 1개의 Q객체가
만들어지고 where node에 들어가게 된다. 1개의 Q객체 내 3개의 조건 데이터를 가지게 됨 3개의 조건 데이터가 Q객체 생성 시점에 정렬 where node에 추가
.filter(a=a, b=b) vs. .filter(a=a).filter(b=b) 3개의 Q객체가 생성, 각 객체가 하나씩의
조건 정렬을 해도 조건이 하나기 때문에 정렬영향을 받지 않음 이후, where node에 호출 순서대로 추가됨
.filter(a=a, b=b) vs. .filter(a=a).filter(b=b) args:() kwargs:{'seller_id': 1} clause: (AND: <django.db.models.fields.related_lookups.RelatedExact
object at 0x124a43c10>) self.where: (AND: <django.db.models.fields.related_lookups.RelatedExact object at 0x124a43c10>) args:() kwargs:{'cooking_day__gte': '2021-08-01'} clause: (AND: <django.db.models.lookups.GreaterThanOrEqual object at 0x124a43820>) self.where: (AND: <django.db.models.fields.related_lookups.RelatedExact object at 0x124a43c10>, <django.db.models.lookups.GreaterThanOrEqual object at 0x124a43820>) args:() kwargs:{'status': 'ORDERED'} clause: (AND: <django.db.models.lookups.Exact object at 0x124a43730>) self.where: (AND: <django.db.models.fields.related_lookups.RelatedExact object at 0x124a43c10>, <django.db.models.lookups.GreaterThanOrEqual object at 0x124a43820>, <django.db.models.lookups.Exact object at 0x124a43730>)
Q를 사용하면 왜 고정될까? .filter 가 호출이 되면 Q가 만들어지고
조건들이 정렬될텐데?
Q를 사용하면 왜 고정될까? args:(<Q: (AND: ('seller_id', 1), ('cooking_day__gte', '2021-08-01'),
('status', 'ORDERED'))>,) kwargs:{} clause: (AND: <django.db.models.fields.related_lookups.RelatedExact object at 0x1623c1850>, <django.db.models.lookups.GreaterThanOrEqual object at 0x1623bdbe0>, <django.db.models.lookups.Exact object at 0x1623bdac0>) self.where: (AND: <django.db.models.fields.related_lookups.RelatedExact object at 0x1623c1850>, <django.db.models.lookups.GreaterThanOrEqual object at 0x1623bdbe0>, <django.db.models.lookups.Exact object at 0x1623bdac0>)
Q를 사용하면 왜 고정될까? args:(<Q: (AND: ('seller_id', 1), ('cooking_day__gte', '2021-08-01'),
('status', 'ORDERED'))>,) kwargs:{} args는 정렬하지 않는다. 작성한 순서대로 where 절의 조건으로 출력
query에 대해서 알아보자
QuerySet.query Q객체 생성 후 self._query.add_q() 함수를 통해서 추가된다.
Query.sql_with_params .query property print시, sql_with_params() 함수 호출 SQLCompiler가 sql을 생성해서
리턴
SQLCompiler 클래스 django.db.models.sql.compiler 다양한 SQLCompiler 가 존재 select,
insert, update, delete, aggregate
SQLCompiler 클래스 as_sql() 함수에서 각 목적에 맞는 쿼리 생성
SQLUpdateCompiler의 예시
Query - SQLCompiler 클래스 Query InsertQuery(Query) UpdateQuery(Query) DeleteQuery(Query) AggregateQuery(Query) SQLCompiler
SQLInsertCompiler(SQLCompiler) SQLUpdateCompiler(SQLCompiler) SQLDeleteCompiler(SQLCompiler) SQLAggregateCompiler(SQLCompiler)
Query - SQLCompiler 클래스
History
왜 Q생성시의 정렬기능을 넣었을까? 의문을 갖게 됨 도대체
왜 Q객체의 생성시, kwargs만 정렬을 할까? 정렬을 하지 않으면, .filter 와 .filter chaining의 결과가 다르지 않을텐데? django는 오픈소스 GitHub를 통해서 추적을 할 수 있다.
django repository https://github.com/django/django/commit/b95c49c954e3b75678bb258e9fb2ec30d0d960bb
code.djangoproject.com https://code.djangoproject.com/ticket/29125
Python 3.6 release note https://docs.python.org/3/whatsnew/3.6.html#pep-468-preserving-keyword-argument-order
결론
처음에 의문을 품었던 3가지 질문 .filter(a=a, b=b) vs. .filter(a=a).filter(b=b)
는 sql문이 왜 다른가? .filter() 함수 호출시 Q객체가 만들어지고 Q객체 생성자에서 조건이 전달되는 kwargs가 오름차순 정렬 작성한 조건 순서가 변경된다.
처음에 의문을 품었던 3가지 질문 Q객체를 사용하면 왜 고정이 될까?
.filter() 함수 호출시 Q객체를 인자로 전달하면 args로 전달이 되게 되고 .filter() 함수에 대한 Q객체 생성시 args는 정렬을 수행하지 않기 때문에 작성한 그대로가 보장된다.
처음에 의문을 품었던 3가지 질문 Django ORM 에서 어떻게 SQL
Where 절의 순서를 고정할까? Q객체의 kwargs 정렬을 피해서 작성하면 된다. - .filter chaining 사용, 1 filter, 1 조건 - Q객체 사용, .filter() 함수에 args로 넘기도록 작성
v 감사합니다