자신의 필드 값을 이용한 annotate 처리
하고 싶은 일
class MyModel(models.Model):
code = models.CharField(max_length=10)
이런 느낌의 모델로,
이런 식으로 같은 코드가 설정되어 있는 수를 세고 싶다.
순진한 해법과 문제점
class MyModelAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'code_count',
)
def code_count(self, obj):
return MyModel.objects.filter(code=obj.code).count()
admin이나 model에 메소드 추가하면 할 수는 있지만
이런 식으로 레코드의 수만큼 sql이 발행된다.
(n+1 문제 발생)
Subquery와 OuterRef를 사용한 annotate
Subquery와 OuterRef를 사용하여 자신의 코드를 사용한 subquery를 발행하면 된다.
from django.contrib import admin
from django.db.models import Count, OuterRef, Subquery
from .models import MyModel
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'code_count',
)
def get_queryset(self, request):
sub_query = MyModel.objects.filter(
code=OuterRef('code')
).values('code').annotate(count=Count('code')).values('count')
return MyModel.objects.annotate(code_count=Subquery(sub_query))
def code_count(self, obj):
return obj.code_count
code=OuterRef('code')
에서 바깥쪽에 있는 자신의 코드로 짜낸다.
code의 수로 카운트를 취하고 싶기 때문에 .values('code')
와 annotate(Count('code'))
로 Group화한다.
sub_query의 결과는 1개가 아니면 안 되므로, 마지막으로 .values('count')
그리고 code
의 카운트수만 돌려준다.
그리고는 code_count
라는 이름으로 앞서 만든 sub_query를 annotate 해 준다.
이것으로 object에 code_count
라는 코드 건수의 attribute가 붙기 때문에, method로 그 값을 돌려주면 완성.
행 수분 발행되고 있던 query가 1개에 정리되었다.
발행되는 sql문은 이런 느낌.
외부 코드를 사용하여 내부에서 code_count
를 만들고 있음을 알 수 있습니다.
조사해도 몰랐는데 코드 쓴 후에 아래의 키워드로 구그 하면 같은 코드가 발견되었다.
django count outerref
Reference
이 문제에 관하여(자신의 필드 값을 이용한 annotate 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/maisuto/items/623b239a527421423532
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class MyModel(models.Model):
code = models.CharField(max_length=10)
class MyModelAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'code_count',
)
def code_count(self, obj):
return MyModel.objects.filter(code=obj.code).count()
admin이나 model에 메소드 추가하면 할 수는 있지만
이런 식으로 레코드의 수만큼 sql이 발행된다.
(n+1 문제 발생)
Subquery와 OuterRef를 사용한 annotate
Subquery와 OuterRef를 사용하여 자신의 코드를 사용한 subquery를 발행하면 된다.
from django.contrib import admin
from django.db.models import Count, OuterRef, Subquery
from .models import MyModel
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'code_count',
)
def get_queryset(self, request):
sub_query = MyModel.objects.filter(
code=OuterRef('code')
).values('code').annotate(count=Count('code')).values('count')
return MyModel.objects.annotate(code_count=Subquery(sub_query))
def code_count(self, obj):
return obj.code_count
code=OuterRef('code')
에서 바깥쪽에 있는 자신의 코드로 짜낸다.
code의 수로 카운트를 취하고 싶기 때문에 .values('code')
와 annotate(Count('code'))
로 Group화한다.
sub_query의 결과는 1개가 아니면 안 되므로, 마지막으로 .values('count')
그리고 code
의 카운트수만 돌려준다.
그리고는 code_count
라는 이름으로 앞서 만든 sub_query를 annotate 해 준다.
이것으로 object에 code_count
라는 코드 건수의 attribute가 붙기 때문에, method로 그 값을 돌려주면 완성.
행 수분 발행되고 있던 query가 1개에 정리되었다.
발행되는 sql문은 이런 느낌.
외부 코드를 사용하여 내부에서 code_count
를 만들고 있음을 알 수 있습니다.
조사해도 몰랐는데 코드 쓴 후에 아래의 키워드로 구그 하면 같은 코드가 발견되었다.
django count outerref
Reference
이 문제에 관하여(자신의 필드 값을 이용한 annotate 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/maisuto/items/623b239a527421423532
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
from django.contrib import admin
from django.db.models import Count, OuterRef, Subquery
from .models import MyModel
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'code_count',
)
def get_queryset(self, request):
sub_query = MyModel.objects.filter(
code=OuterRef('code')
).values('code').annotate(count=Count('code')).values('count')
return MyModel.objects.annotate(code_count=Subquery(sub_query))
def code_count(self, obj):
return obj.code_count
Reference
이 문제에 관하여(자신의 필드 값을 이용한 annotate 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/maisuto/items/623b239a527421423532텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)