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
270
Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?
AhnSeongHyun
August 15, 2023
Tweet
Share
More Decks by AhnSeongHyun
See All by AhnSeongHyun
개발자 커리어 : 두려움이 이끄는 대로
ahnseonghyun
0
1.6k
개발자는 어떤 일을 하는 걸까?
ahnseonghyun
0
460
SQLAlchemy CustomTypes
ahnseonghyun
0
940
5번째 회사 그리고 레이니스트
ahnseonghyun
0
230
리부트 : 경력자에게도 수습이 필요한 순간
ahnseonghyun
0
2.4k
MQTT 를 이용한 주문 시스템 개선
ahnseonghyun
0
1.2k
CNN MNIST Tutorial
ahnseonghyun
0
91
github:유용한 기능들
ahnseonghyun
0
1.8k
카피캣으로 시작하는 오픈소스
ahnseonghyun
0
1.4k
Other Decks in Programming
See All in Programming
エンジニア向け採用ピッチ資料
inusan
0
160
プロダクト志向ってなんなんだろうね
righttouch
PRO
0
160
Julia という言語について (FP in Julia « SIDE: F ») for 関数型まつり2025
antimon2
3
980
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
650
git worktree × Claude Code × MCP ~生成AI時代の並列開発フロー~
hisuzuya
1
500
Rubyでやりたい駆動開発 / Ruby driven development
chobishiba
1
460
0626 Findy Product Manager LT Night_高田スライド_speaker deck用
mana_takada
0
110
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
140
すべてのコンテキストを、 ユーザー価値に変える
applism118
2
890
エラーって何種類あるの?
kajitack
5
310
プロダクト志向なエンジニアがもう一歩先の価値を目指すために意識したこと
nealle
0
110
型付きアクターモデルがもたらす分散シミュレーションの未来
piyo7
0
810
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
17
940
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
The Cult of Friendly URLs
andyhume
79
6.5k
We Have a Design System, Now What?
morganepeng
53
7.7k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
657
60k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
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 감사합니다