[Django 3일차] Django Race Condition 해결 및 삭제 기능 구현 3/4 (short_url 프로젝트)(250514)

2025. 5. 14. 15:28·특강

🚦 Django에서의 Race Condition 해결 및 삭제 기능 구현 튜토리얼

Django 웹 개발 시 자주 마주하는 엑세스 카운트 처리 문제와 삭제 요청 처리 방식, 그리고 좋은 코드 구조 설계 원칙까지 단계별로 정리합니다.


1. ⚙️ 장고에서의 엑세스 카운트 처리와 레이스 컨디션

1.1 🧨 문제 상황 설명

  • 엑세스 카운트를 Python 코드에서 +1 하는 방식은 아래와 같은 흐름을 가집니다:
  • short_url.access_count += 1 short_url.save()
  • 문제점:
    • DB에서 값을 먼저 읽어옴 → 파이썬에서 +1 연산 → 다시 저장
    • 동시에 요청이 들어올 경우, 둘 다 이전 값을 기반으로 연산하여 카운트가 덜 증가하는 문제가 발생함

1.2 🎯 Race Condition(경쟁 상태)

  • 동일한 자원에 대해 동시 접근 시 결과가 엉킬 수 있는 상황을 의미
  • Django 개발 서버는 요청을 순차 처리하지만, 실제 배포 환경(예: gunicorn 등 WSGI 서버)은 동시 요청을 처리함 → 실제 문제 발생 가능

1.3 ✅ 해결 방법: F 표현식 사용

from django.db.models import F

short_url.access_count = F("access_count") + 1
short_url.save()
  • Django의 F() 표현식은 DB에서 직접 연산을 수행함
  • Python에서 값을 가져오는 것과 달리, 현재 DB 상태를 기준으로 덧셈 연산이 실행됨
  • 결과적으로 Race Condition 방지 가능

📌 실제 적용 예시는 아래와 같음:

from django.db.models import F
from django.shortcuts import get_object_or_404

short_url = get_object_or_404(ShortURL, code=code)
short_url.access_count = F('access_count') + 1
short_url.save()

2. 🗑️ 삭제 기능 구현: HTTP 메서드 분리 처리

2.1 🔄 GET vs DELETE

  • REST 원칙에 따라, 특정 자원 삭제 시 DELETE 요청을 사용하는 것이 적절함
  • 하지만 HTML form은 GET과 POST 메서드만 지원

2.2 ✨ 해결 방법: POST 방식으로 삭제 요청 처리

  • 뷰 코드에서 POST 요청을 감지하여 삭제 수행
# views.py
from django.shortcuts import redirect

if request.method == 'POST':
    short_url.delete()
    return redirect('home')
  • HTML 폼:
<form method="POST" action="{% url 'shortener:detail' short_url.code %}">
  {% csrf_token %}
  <button type="submit" class="btn btn-danger btn-sm">삭제</button>
</form>
  • URL 패턴은 그대로 유지:
path('<str:code>/', views.short_url_detail, name='detail')

3. 🗂️ 삭제 버튼 추가: HTML 구현

3.1 🔧 테이블 내 삭제 버튼 구성

<thead>
  <tr>
    <th>URL</th>
    <th>생성일</th>
    <th>액션</th>
  </tr>
</thead>
<tbody>
  {% for short_url in url_list %}
    <tr>
      <td>{{ short_url.original_url }}</td>
      <td>{{ short_url.created_at }}</td>
      <td>
        <form method="POST" action="{% url 'shortener:detail' short_url.code %}">
          {% csrf_token %}
          <button class="btn btn-danger btn-sm" type="submit">삭제</button>
        </form>
      </td>
    </tr>
  {% endfor %}
</tbody>

📌 주의 사항

  • action에는 URL을 정확히 지정해야 함 → short_url.code 등 포함
  • CSRF 토큰 반드시 포함 필요

4. ✏️ HTTP 메서드와 CSRF 토큰 처리

4.1 POST 방식에서의 보안 처리

  • HTML 폼은 GET, POST만 지원
  • POST 방식 사용 시 csrf_token을 반드시 포함해야 보안상 안전함
<form method="POST" action="...">
  {% csrf_token %}
  <button type="submit">삭제</button>
</form>
  • CSRF 미포함 시, Django는 요청을 거부함 (403 Forbidden)

5. 🧑‍💻 좋은 코드 설계: 뷰 분리와 함수 단일 책임 원칙

문제 상황:

if request.method == 'GET':
    return redirect(short_url.original_url)
elif request.method == 'POST':
    short_url.delete()
    return redirect('home')
  • GET 요청은 리디렉션, POST 요청은 삭제 처리
  • 두 가지 기능이 하나의 뷰에서 처리되며, 함수의 책임이 모호함

🛠 개선 방법: 기능별 함수 분리

# redirect view
path('<str:code>/go/', views.redirect_view, name='redirect')

# delete view
path('<str:code>/delete/', views.delete_view, name='delete')
  • 각각의 기능을 별도의 함수/클래스 기반 뷰로 분리하여 가독성과 유지보수성 향상

✅ 정리

항목 설명

Race Condition 동시에 요청 시 DB 데이터 충돌 가능성
해결책 F 표현식 활용해 DB에서 직접 연산 수행
삭제 요청 HTML 폼은 POST만 지원하므로 POST로 구현
CSRF POST 요청에는 csrf_token 필수
좋은 코드 한 뷰에서 여러 기능을 처리하지 않고 기능별로 분리 구성

이 구조를 통해 Django에서의 동시성 이슈와 RESTful 방식 삭제 처리, 그리고 코드 유지보수성을 한층 높일 수

'특강' 카테고리의 다른 글

[Django 4일차] Django를 백엔드 프레임워크로 활용하기 - DRF 입문 가이드 1/4 (short_url 프로젝트)(250515)  (0) 2025.05.15
[Django 3일차] Django 함수형 뷰 vs 클래스형 뷰 + ORM 4/4 (short_url 프로젝트)(250514)  (0) 2025.05.14
[Django 2일차] Django로 만드는 숏 URL 생성기 4/4 (250513)  (0) 2025.05.13
[Django 2일차] Django로 숏 URL 생성 서비스 만들기 3/4 (250513)  (0) 2025.05.13
[Django 2일차] Django 마이그레이션과 ORM 실전 이해 가이드2/4 (250513)  (0) 2025.05.13
'특강' 카테고리의 다른 글
  • [Django 4일차] Django를 백엔드 프레임워크로 활용하기 - DRF 입문 가이드 1/4 (short_url 프로젝트)(250515)
  • [Django 3일차] Django 함수형 뷰 vs 클래스형 뷰 + ORM 4/4 (short_url 프로젝트)(250514)
  • [Django 2일차] Django로 만드는 숏 URL 생성기 4/4 (250513)
  • [Django 2일차] Django로 숏 URL 생성 서비스 만들기 3/4 (250513)
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (702)
      • Python (32)
      • 프로젝트 (43)
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (40)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (4)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
[Django 3일차] Django Race Condition 해결 및 삭제 기능 구현 3/4 (short_url 프로젝트)(250514)
상단으로

티스토리툴바