Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?

Django ORM에서는 어떻게 SQL Where절 조건 순서를 고정할 수 있을까?

AhnSeongHyun

August 15, 2023
Tweet

More Decks by AhnSeongHyun

Other Decks in Programming

Transcript

  1. v 목차 Trigger 
 
 Django ORM 이 SQL이 되기까지

    
 
 History 
 
 결론
 

  2. 발표자 소개 
 안성현 @sh84ahn
 페이히어 CTO (2020~) 
 뱅크샐러드

    송금 테크리드 
 백엔드 개발자, 글쓰기
 ash84.io
 
 
 
 
 

  3. Trigger
 Q객체를 쓰면 순서가 바뀌지 않는다는 제보
 
 사내 블로그를

    쓰기로 했지만
 
 블로그는 쓰지않고…. 😇
 파이콘 발표로 이어지는데… 

  4. ORM에서 어떻게 where절의 순서를 고정할까? where절의 순서를 고정할 필요는 없다.

    
 
 그러나, 
 당연히 .filter(a=a, b=b) 로 하면 where a=’a’ and b=’b’ 로 SQL을 생성하지 않을까?
 
 작성한 순서대로 출력하지 않으면, 
 Django ORM은 어떤 기준으로 순서를 변경할까? 🧐
 
 Django Official Site에서 해당 내용을 찾지 못함 
 
 
 

  5. filter() 함수 내 combined_quires 예제 
 django.db.utils.NotSupportedError: Calling QuerySet.filter() after

    union() is not supported. 
 union, difference, intersection 같은 함수 이후에 filter 사용시 에러 발생 
 

  6. QuerySet._filter_or_exclude_inplace negate : 부정 여부 
 negate 여부에 따라 ~Q

    또는 Q 객체를 생성
 Query의 add_q() 함수 호출 

  7. QuerySet._filter_or_exclude_inplace args:() kwargs:{'seller_id': 1, 'cooking_day__gte': '2021-08-01', 'status': 'ORDERED'} 
 filter

    함수에서 전달한 조건들이 kwargs를 통해서 Q까지 전달 
 filter 함수는 내부적으로 Q객체를 만들고 _query 에 추가 
 

  8. 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') ]
  9. QuerySet에 대한 복사본을 생성 반환하는 역할
 해당 복사본에 filter로 전달된

    조건들(kwargs)을 Q객체로 생성됨
 생성 시점에 조건들에 대해서 정렬(sorted) 수행 
 해당 복사본의 _query에 생성한 Q객체를 추가 
 
 filter 정리 

  10. .filter(a=a, b=b) vs. .filter(a=a).filter(b=b) 
 filter() 함수를 호출하면 1개의 Q객체가

    만들어지고 where node에 들어가게 된다. 
 1개의 Q객체 내 3개의 조건 데이터를 가지게 됨 
 3개의 조건 데이터가 Q객체 생성 시점에 정렬 
 where node에 추가 
 

  11. .filter(a=a, b=b) vs. .filter(a=a).filter(b=b) 3개의 Q객체가 생성, 각 객체가 하나씩의

    조건
 정렬을 해도 조건이 하나기 때문에 정렬영향을 받지 않음 
 이후, where node에 호출 순서대로 추가됨 
 

  12. .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>)
  13. 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>)
  14. Q를 사용하면 왜 고정될까? args:(<Q: (AND: ('seller_id', 1), ('cooking_day__gte', '2021-08-01'),

    ('status', 'ORDERED'))>,) kwargs:{} args는 정렬하지 않는다. 
 작성한 순서대로 where 절의 조건으로 출력 

  15. Query - SQLCompiler 클래스 Query InsertQuery(Query) UpdateQuery(Query) DeleteQuery(Query) AggregateQuery(Query) SQLCompiler

    SQLInsertCompiler(SQLCompiler) SQLUpdateCompiler(SQLCompiler) SQLDeleteCompiler(SQLCompiler) SQLAggregateCompiler(SQLCompiler)
  16. 왜 Q생성시의 정렬기능을 넣었을까? 
 의문을 갖게 됨 
 도대체

    왜 Q객체의 생성시, kwargs만 정렬을 할까? 
 정렬을 하지 않으면, .filter 와 .filter chaining의 결과가 다르지 않을텐데? 
 
 django는 오픈소스 
 GitHub를 통해서 추적을 할 수 있다. 

  17. 처음에 의문을 품었던 3가지 질문 
 .filter(a=a, b=b) vs. .filter(a=a).filter(b=b)

    는 sql문이 왜 다른가? 
 
 .filter() 함수 호출시 Q객체가 만들어지고 
 Q객체 생성자에서 조건이 전달되는 kwargs가 오름차순 정렬
 작성한 조건 순서가 변경된다. 

  18. 처음에 의문을 품었던 3가지 질문 Q객체를 사용하면 왜 고정이 될까?

    
 
 .filter() 함수 호출시 Q객체를 인자로 전달하면 
 args로 전달이 되게 되고 .filter() 함수에 대한 Q객체 생성시 
 args는 정렬을 수행하지 않기 때문에 작성한 그대로가 보장된다. 
 

  19. 처음에 의문을 품었던 3가지 질문 Django ORM 에서 어떻게 SQL

    Where 절의 순서를 고정할까?
 
 Q객체의 kwargs 정렬을 피해서 작성하면 된다. 
 - .filter chaining 사용, 1 filter, 1 조건
 - Q객체 사용, .filter() 함수에 args로 넘기도록 작성