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
210
Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?
AhnSeongHyun
August 15, 2023
Tweet
Share
More Decks by AhnSeongHyun
See All by AhnSeongHyun
개발자 커리어 : 두려움이 이끄는 대로
ahnseonghyun
0
1.5k
개발자는 어떤 일을 하는 걸까?
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
77
github:유용한 기능들
ahnseonghyun
0
1.7k
카피캣으로 시작하는 오픈소스
ahnseonghyun
0
1.4k
Other Decks in Programming
See All in Programming
103 Early Hints
sugi_0000
1
220
あれやってみてー駆動から成長を加速させる / areyattemite-driven
nashiusagi
1
200
開発者とQAの越境で自動テストが増える開発プロセスを実現する
92thunder
1
180
数十万行のプロジェクトを Scala 2から3に完全移行した
xuwei_k
0
260
useSyncExternalStoreを使いまくる
ssssota
6
1k
From Translations to Multi Dimension Entities
alexanderschranz
2
130
N.E.X.T LEVEL
pluu
2
300
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
180
暇に任せてProxmoxコンソール 作ってみました
karugamo
1
710
Webエンジニア主体のモバイルチームの 生産性を高く保つためにやったこと
igreenwood
0
330
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
610
「Chatwork」Android版アプリを 支える単体テストの現在
okuzawats
0
180
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
4 Signs Your Business is Dying
shpigford
181
21k
Imperfection Machines: The Place of Print at Facebook
scottboms
266
13k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Making the Leap to Tech Lead
cromwellryan
133
9k
Faster Mobile Websites
deanohume
305
30k
GraphQLとの向き合い方2022年版
quramy
44
13k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Building a Scalable Design System with Sketch
lauravandoore
460
33k
BBQ
matthewcrist
85
9.4k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
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 감사합니다