django에서 모델 데이터 변경이력을 관리할 때는 주로 simple history를 사용합니다.
simple history: https://django-simple-history.readthedocs.io/en/latest/
simple history를 사용하면 쉽게 데이터 이력을 관리할 수 있지만, 변경이 잦을 경우 데이터가 지나치게 많이 쌓여 DB 리소스 낭비와 조회 속도 저하 등의 문제점이 있습니다.
FieldTracker와 Signal을 사용하여 더 효율적으로 변경 이력을 관리할 수 있습니다.
FieldTracker
FieldTracker는 모델의 특정 필드의 변경 사항을 추적하는 유틸성 필드입니다.
FieldTracker는 django-model-utils 패키지에서 제공됩니다.
from django.db import models
from model_utils import FieldTracker
from simple_history.models import HistoricalRecords
class Product(models.Model):
name = models.CharField(max_length=255, verbose_name="Product Name")
price = models.PositiveIntegerField(default=0)
stock = models.PositiveIntegerField(default=0)
description = models.TextField(null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True)
history = HistoricalRecords()
tracker = FieldTracker(fields=["price"]) # price 필드 변경 추적
위 Product 모델은 name, price, stock, description과 같은 필드가 있고 simple history로 변경이력을 관리합니다.
이때 FieldTracker(fields=["price"])
와 같이 fields에 리스트 형태로 트래킹할 필드를 입력합니다.
예제에서는 price 필드를 트래킹할 수 있습니다.
Signal
from django.db.models.signals import pre_save
from django.dispatch import receiver
@receiver(pre_save, sender=Product)
def track_price_history(sender, instance, **kwargs):
"""
제품의 가격(price)이 변경될 때만 이력을 기록
"""
instance.skip_history_when_saving = True
if instance.tracker.has_changed("price"):
del instance.skip_history_when_saving
Signal에서는 모델이 저장되기 전에 tracker 필드를 통해 price 필드의 변경 여부를 체크합니다.
만약 price가 변경되었다면 FieldTracker에 의해 tracker.has_changed("price")
는 True를 반환합니다.
예제의 skip_history_when_saving
는 simple history가 데이터 저장 시 history 데이터를 생성할지 결정하는 필드입니다. 따라서 price가 변경될 때만 history를 생성하도록 처리하였습니다.
product = Product.objects.get(name="my_product")
print(product.history.count() == 1) # True
# history 생성되지 않음
product.stock = 100
product.save()
print(product.history.count() == 1) # True
# history 생성
product.price = 1000
product.save()
print(product.history.count() == 2) # True
최종적으로 위 예시와 같이 price를 변경 때만 history를 생성할 수 있습니다.
위 예제와 같이 FieldTracker와 Signal을 활용하면 django-simple-history의 기능을 유지하면서도 불필요한 데이터 저장을 줄일 수 있습니다.
1. 빈번한 데이터 변경이 발생하는 경우: 불필요한 데이터는 이력을 쌓지 않음으로써 DB 크기와 리소스를 절약할 수 있습니다.
2. 특정 필드 중심의 변경 관리: 중요한 필드(예: 가격, 상태 등)만 변경 이력을 저장하여 로그 조회 시 필드 변경 사항 추적에 용이합니다.
3. 이력 관리 후처리가 필요한 경우: Signal을 통해 이력 생성 후 추가 작업(예: 알림 발송, 로그 파일 기록 등)을 수행할 수 있습니다.
'Django' 카테고리의 다른 글
Django 다중 서버 환경 동시성 제어하기(select_for_update/redis lock) (0) | 2025.02.23 |
---|---|
Django에서 JSON 파일로 동적 상수 클래스를 생성하기 (3) | 2025.02.01 |
Django TextChoices로 상수 관리하기 (4) | 2025.01.05 |