




# transaction/view_html.py
@login_required
def transaction_html_view(request):
qs = Transaction.objects.filter(user=request.user)
# 카테고리 필터
category = request.GET.get("category")
if category:
qs = qs.filter(category=category)
# 기간 필터
start = request.GET.get("start")
end = request.GET.get("end")
if start:
qs = qs.filter(transacted_at__date__gte=start)
if end:
qs = qs.filter(transacted_at__date__lte=end)
qs = qs.order_by('-created_at')
return render(request, "transactions/transaction_list.html", {
"transactions": qs,
})
# templates/transaction/transaction_list.html
<!-- 필터기능 추가 -->
<div class="card shadow-sm p-3 mb-4">
<form method="GET" class="row g-3">
<!-- 카테고리 -->
<div class="col-md-3">
<label class="form-label fw-semibold">카테고리</label>
<select name="category" class="form-select">
<option value="">전체</option>
<option value="food" {% if request.GET.category == "food" %}selected{% endif %}>식비</option>
<option value="transport" {% if request.GET.category == "transport" %}selected{% endif %}>교통</option>
<option value="shopping" {% if request.GET.category == "shopping" %}selected{% endif %}>쇼핑</option>
<option value="income" {% if request.GET.category == "income" %}selected{% endif %}>수입</option>
<option value="etc" {% if request.GET.category == "etc" %}selected{% endif %}>기타</option>
</select>
</div>
<!-- 시작 날짜 -->
<div class="col-md-3">
<label class="form-label fw-semibold">시작 날짜</label>
<input type="date"
name="start"
class="form-control"
value="{{ request.GET.start }}">
</div>
<!-- 종료 날짜 -->
<div class="col-md-3">
<label class="form-label fw-semibold">종료 날짜</label>
<input type="date"
name="end"
class="form-control"
value="{{ request.GET.end }}">
</div>
<!-- 버튼 -->
<div class="col-md-3 d-flex align-items-end">
<button class="btn btn-dark w-100 py-2">
🔍 필터 적용
</button>
</div>
</form>
</div>
비동기 작업 및 작업 대기열을 관리하는 Python 기반의 분산 메시지 큐 시스템
주로 백그라운드 작업 처리, 비동기 작업 처리, 그리고 스케줄링된 작업을 처리하는 데 사용
Celery는 분산 시스템이기 때문에 여러 노드에서 동시에 작업을 처리할 수 있어 확장성이 뛰어나며,
celery beat라는 스케줄러가 필요Redis나 RabbitMQ가 이 역할을 자주 수행from celery.schedules import crontab
app.conf.beat_schedule = {
'add-every-midnight': {
'task': 'tasks.add',
'schedule': crontab(minute=0, hour=0),
'args': (16, 16),
},
}
from celery import Celery
app = Celery('my_project', broker='redis://localhost:6379/0',
backend='redis://localhost:6379/0')
@app.task
def add(x, y):
return x + y
result = add.delay(4, 6)poetry add django-celery-beatdjango-celery-beat 를 설치 불가django-timezone-field 라이브러리가 
| 구분 | @app.task | @shared_task |
|---|---|---|
| Celery 앱 필요? | 필요함 (app 인스턴스 기반) | 필요 없음 (프로젝트 어디서나 사용 가능) |
| 추천 용도 | 단일 앱 형태의 Celery 구성 | Django의 여러 앱에서 task 를 사용할 때 |
| 장점 | 명시적이고 구조적임 | Django 프로젝트에서 가장 많이 사용됨 |
from celery import shared_task
from django.contrib.auth import get_user_model
from .analyzers import Analyzer
from .utils import get_daily_range
User = get_user_model()
@shared_task
def create_daily_analysis(user_id):
"""특정 사용자에 대한 DAILY 분석을 자동으로 생성"""
user = User.objects.get(id=user_id)
start_date, end_date = get_daily_range()
analyzer = Analyzer(
user=user,
about="TOTAL_SPENDING",
period_type="DAILY",
start_date=start_date,
end_date=end_date,
description="자동으로 생성된 매일 분석",
graph_type="CATEGORY",
)
result = analyzer.run()
return f"Analysis created: {result.id}"

from analysis.tasks import create_daily_analysis
class AnalysisCreateView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
task = create_daily_analysis.delay(request.user.id)
return Response({
"message": "분석 생성이 요청되었습니다.",
"task_id": task.id
})

Django Signal
특정 이벤트가 발생할 때 다른 부분에서 알림을 받아 추가 작업을 수행할 수 있도록 하는 기능
pre_save: 모델의 인스턴스가 저장되기 전에 호출post_save: 모델의 인스턴스가 저장된 후에 호출pre_delete: 모델의 인스턴스가 삭제되기 전에 호출post_delete: 모델의 인스턴스가 삭제된 후에 호출m2m_changed: 다대다 관계가 변경될 때 호출request_started: HTTP 요청이 시작될 때 호출request_finished: HTTP 요청이 끝났을 때 호출sender / **kwargs.from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel
# 수신기 함수 정의
@receiver(post_save, sender=MyModel)
def my_model_post_save(sender, instance, created, **kwargs):
if created:
print(f"{instance}이(가) 생성되었습니다!")
else:
print(f"{instance}이(가) 수정되었습니다!")
@receiver 데코레이터를 사용 가능signals.connect() 메서드를 사용해 시그널과 수신기를 명시적으로 연결도 가능from django.db.models.signals import post_save
from django.dispatch import receiver
from myapp.models import MyModel
# 시그널과 수신기 연결
@receiver(post_save, sender=MyModel)
def my_model_post_save(sender, instance, created, **kwargs):
# 저장된 후 처리할 로직
if created:
print(f"새 인스턴스 {instance}가 생성되었습니다!")
내장 시그널 외에도 사용자 정의 시그널을 만들어 특정 이벤트가 발생했을 때 알림을 발송 가능
Django의 Signal 클래스를 사용하여 사용자 정의 시그널을 정의 가능
from django.dispatch import Signal
# 사용자 정의 시그널 정의
my_custom_signal = Signal(providing_args=["arg1", "arg2"])
from django.dispatch import receiver
@receiver(my_custom_signal)
def handle_my_custom_signal(sender, **kwargs):
print("사용자 정의 시그널이 호출되었습니다!")
print(f"인자: {kwargs}")
# 시그널 발송
my_custom_signal.send(sender=None, arg1="Hello", arg2="World")
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from myapp.models import Profile
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
from django.db.models.signals import pre_delete, post_delete
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(pre_delete, sender=MyModel)
def before_model_delete(sender, instance, **kwargs):
print(f"{instance}이(가) 삭제되기 전입니다.")
@receiver(post_delete, sender=MyModel)
def after_model_delete(sender, instance, **kwargs):
print(f"{instance}이(가) 삭제된 후입니다.")