django template cache 사용방법 (MPTT 적용)
사전 작업
settings.py 설정
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
"KEY_PREFIX": "devspoon",
}
}
# Cache time to live is 15 minutes.
CACHE_TTL = 60 * 15
SESSION_ENGINE = "django.contrib.sessions.backends.cache" # use only cache
SESSION_CACHE_ALIAS = "default"
Template에 cache 선언
{% load cache %}
.
.
# 원하는 코드 구간
# template_main_menu_pc 는 키 값이 됨
{% cache 604800 template_main_menu_pc %}
.
# 이 구간이 캐시가 됨
.
{% endcache %}
* MTPP의 경우 아래 코드에서 지속적으로 쿼리가 발생함
- 코드 분석 결과 유무를 확인하는 과정이기에 캐시로 구현하기 복잡할 것으로 예상됨
- 최적화, 고성능을 위해서는 MTPP 패키지를 쓰는건 옳지 않다는 것을 알고 있기에 template, templatetag에서 캐시를 통해 9회 이상의 캐시를 3회로 낮춘것으로 만족하기로 함
- 대처안 : 단계형으로 구분 가능한 딕셔너리를 전송 및 캐싱하고, javascript로 구현하는게 좋다.
* 이전에 모델에서 cached_property로 구현한 사례를 본적이 있으나 현재 다시 찾지를 못해 적용을 못해봄
{% if not node.get_next_sibling %}
Templatetags에 적용
from django import template
from django.conf import settings
from django.core.cache import cache
from django.core.cache.backends.base import DEFAULT_TIMEOUT
from home.models.default import MainMenu, SiteInfo
CACHE_TTL = getattr(settings, "CACHE_TTL", DEFAULT_TIMEOUT)
@register.simple_tag
def main_menu_tag():
if "main_menu" in cache:
main_menu = cache.get("main_menu") # 캐시 가져오기
else:
main_menu = MainMenu.objects.all()
cache.set("main_menu", main_menu, timeout=CACHE_TTL) # 캐시 저장
return main_menu
Admin에 적용
- menu의 생성, 업데이트, 삭제는 모두 admin에서만 발생한다.
- admin에서 어떤 작업을 하던 캐시를 모두 날려주는 작업을 오버라이딩 하고 캐시만 날려주는 메뉴도 구현하기로 한다.
* 작업을 하면서 알게 된 것으로 리스트 페이지에서 모든 작업은 하나 이상의 아이템이 선택 되어 있는 상태여야 트리거가 동작한다.
class MainMenuAdmin(DraggableMPTTAdmin):
actions = [
"delete_all_of_main_cache",
"delete_selected_items",
]
# 리팩토링으로 캐시 클린을 정의함
def delete_menu_cache(self):
cache.delete("main_menu")
key = make_template_fragment_key("template_main_menu_pc")
cache.delete(key)
# 기존 delete_selected 메뉴 삭제 (리스트 페이지)
def get_actions(self, request):
actions = super(MainMenuAdmin, self).get_actions(request)
del actions["delete_selected"]
return actions
# delete_selected 메뉴 대체
def delete_selected_items(self, request, queryset):
for obj in queryset:
self.delete_menu_cache()
obj.delete()
# 캐시만 삭제, 꼭 하나의 아이템이 선택 되어야 트리거가 동작한다
def delete_all_of_main_cache(self, request, queryset):
self.delete_menu_cache()
# 생성, 업데이트 오버라이딩
def save_model(self, request, obj, form, change):
self.delete_menu_cache()
super().save_model(request, obj, form, change)
# 삭제 오버라이딩 (상세 페이지에서 삭제)
def delete_model(self, request, obj):
self.delete_menu_cache()
super().delete_model(request, obj)
* 상위 코드는 현재 개발중인 프로젝트에 확인할 수 있다.
- 소스가 많은 편이니 전체 찾기에서 함수명을 이용하면 된다.
https://github.com/devspoon/devspoon-portfolio-blog
* chatGPT로 오버라이딩 관련 질문을 해서 참고를 했는데 save 관련 코드는 쓸만했으나 delete 관련은 설명이 부족했었다. 하지만 반복된 구체적 질문을 하게 되면 원하는 답을 유도할 수 있을것 같았다. (stackoverflow에서 그냥 검색해서 해결함)
reference
https://runebook.dev/ko/docs/django/topics/cache?page=3
https://books.agiliq.com/projects/django-admin-cookbook/en/latest/remove_delete_selected.html
https://books.agiliq.com/projects/django-admin-cookbook/en/latest/override_save.html
https://stackoverflow.com/questions/15196313/django-admin-override-delete-method
'Django Web Framework > Django 일반' 카테고리의 다른 글
웹 애플리케이션의 성능 지표 및 측정 (측정 도구) (0) | 2024.02.01 |
---|---|
django에서 db row lock을 실행할 수 있는 방법 (0) | 2023.12.18 |
Django migrate 잘 쓰기 위한 정리 노트 (0) | 2023.12.15 |
allauth를 사용해 production 등록을 할 때 400 error가 발생하는 경우 (0) | 2023.08.09 |
Django 로깅 적용하기 (0) | 2021.07.07 |
댓글