[장고] id가 아닌 특정 필드로 제네릭 뷰 사용하기

소요 시간: 10분

Django에서 제네릭 뷰(CreateView, DetailView, UpdateView, DeleteView)는 기본적으로 id를 사용하여 객체를 식별합니다. 또한 특정 필드 값을 기준으로 사용하도록 설정할 수 있습니다.


장고 제네릭 뷰

장고(Django)에서 제네릭(Generic) 뷰는 웹 애플리케이션의 공통 패턴을 간소화하고 중복 코드를 줄이기 위해 제공되는 클래스 기반 뷰입니다. 제네릭 뷰를 사용하면 CRUD(Create, Read, Update, Delete) 작업을 쉽게 처리할 수 있습니다.

제네릭 뷰의 종류

  1. ListView: 데이터베이스의 객체 목록을 보여주는 뷰입니다.
  2. DetailView: 단일 객체의 상세 정보를 보여주는 뷰입니다.
  3. CreateView: 새로운 객체를 생성하는 뷰입니다.
  4. UpdateView: 기존 객체를 수정하는 뷰입니다.
  5. DeleteView: 기존 객체를 삭제하는 뷰입니다.

ID와 관련된 제네릭 뷰 사용 예시

DetailView와 같은 뷰에서는 URL에 객체의 ID를 포함하여 특정 객체를 조회하는 것이 일반적입니다. 예를 들어, 특정 글의 상세 페이지를 보여주는 뷰를 설정할 때 사용되는 방법입니다.

DetailView 예시

from django.views.generic.detail import DetailView
from .models import Post

class PostDetailView(DetailView):
    model = Post
    template_name = 'post_detail.html'

이렇게 설정된 뷰는 URL 패턴에서 객체의 ID를 사용하여 특정 객체를 조회합니다.

URL 설정

from django.urls import path
from .views import PostDetailView

urlpatterns = [
    path('post/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]

이 URL 설정은 post/1/과 같은 URL 요청이 들어오면 ID가 1인 Post 객체를 조회하여 PostDetailView에 전달합니다. 여기서 pk는 기본 키(primary key)를 의미하며, Django는 이를 통해 데이터베이스에서 해당 객체를 찾습니다.

제네릭 뷰의 동작 원리

  1. URL에서 ID 추출: URL 패턴에서 <int:pk>/와 같은 구문을 사용하여 객체의 ID를 추출합니다.
  2. 객체 조회: DetailView는 전달된 ID를 사용하여 데이터베이스에서 해당 객체를 조회합니다.
  3. 컨텍스트에 추가: 조회된 객체는 컨텍스트에 추가되어 템플릿에서 사용할 수 있습니다.
  4. 템플릿 렌더링: 지정된 템플릿 파일을 렌더링하여 사용자에게 응답합니다.

ID 관련 필터링

제네릭 뷰는 기본적으로 ID로 객체를 조회하지만, 필터링을 커스터마이징할 수도 있습니다. 예를 들어, 다른 필드로 객체를 조회하려면 get_queryset 메서드를 오버라이드할 수 있습니다.

from django.views.generic.detail import DetailView
from .models import Post

class PostDetailView(DetailView):
    model = Post
    template_name = 'post_detail.html'

    def get_queryset(self):
        return Post.objects.filter(status='published')

이렇게 하면 status가 published인 Post 객체만 조회 대상이 됩니다.

장고의 제네릭 뷰와 ID를 사용하는 방식은 웹 애플리케이션 개발에서 코드의 재사용성과 가독성을 높이는 데 큰 도움이 됩니다. 이를 통해 개발자는 더 적은 코드로 더 많은 기능을 효율적으로 구현할 수 있습니다.


특정 필드를 제네릭 뷰의 식별자로 사용하는 방법

다만, id는 예측 가능하고 일관성이 있어 보안에 취약할 수 있습니다. 대신 유니크한 문자열을 사용하면 예측이 어려워 공격자가 특정 객체에 접근하기 힘듭니다. 또한 id는 데이터베이스에 종속적이지만, 유니크한 문자열은 논리적 식별자로 데이터베이스 변경 시에도 URL 구조를 유지할 수 있습니다.

따라서 unique_field라는 가상의 식별자 필드를 기준으로 데이터를 업데이트, 상세 조회, 삭제하는 방법을 설명하겠습니다.

1. models.py 설정

먼저, 사용될 가상의 모델을 정의합니다. 이 모델에는 unique_field라는 유니크한 필드가 포함됩니다.

from django.db import models

class YourModel(models.Model):
    unique_field = models.CharField(max_length=100, unique=True)
    field1 = models.CharField(max_length=100)
    field2 = models.TextField()
    field3 = models.IntegerField()

    def __str__(self):
        return self.unique_field

2. urls.py 설정

먼저 URL 패턴을 설정하여 뷰를 연결합니다. unique_field 값을 URL 경로에서 받아오도록 설정합니다.

from django.urls import path
from .views import UniqueFieldDetailView, UniqueFieldUpdateView, UniqueFieldDeleteView

urlpatterns = [
    path('detail/<str:unique_field>/', UniqueFieldDetailView.as_view(), name='detail-by-unique-field'),
    path('update/<str:unique_field>/', UniqueFieldUpdateView.as_view(), name='update-by-unique-field'),
    path('delete/<str:unique_field>/', UniqueFieldDeleteView.as_view(), name='delete-by-unique-field'),
]

3. views.py 설정

DetailView, UpdateView, DeleteView를 상속받아 새로운 뷰를 생성합니다. get_object 메서드를 오버라이드하여 unique_field 값을 기준으로 객체를 가져옵니다.

from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.views.generic import DetailView
from django.views.generic.edit import UpdateView, DeleteView
from .models import YourModel
from .forms import YourModelForm

class UniqueFieldDetailView(DetailView):
    model = YourModel
    template_name = 'yourapp/yourmodel_detail.html'

    def get_object(self, queryset=None):
        unique_field = self.kwargs.get('unique_field')
        return get_object_or_404(YourModel, unique_field=unique_field)

class UniqueFieldUpdateView(UpdateView):
    model = YourModel
    form_class = YourModelForm
    template_name = 'yourapp/yourmodel_form.html'
    success_url = reverse_lazy('success-url')

    def get_object(self, queryset=None):
        unique_field = self.kwargs.get('unique_field')
        return get_object_or_404(YourModel, unique_field=unique_field)

class UniqueFieldDeleteView(DeleteView):
    model = YourModel
    template_name = 'yourapp/yourmodel_confirm_delete.html'
    success_url = reverse_lazy('success-url')

    def get_object(self, queryset=None):
        unique_field = self.kwargs.get('unique_field')
        return get_object_or_404(YourModel, unique_field=unique_field)

4. forms.py 설정 (필요한 경우)

폼 클래스를 정의하여 업데이트할 필드를 지정합니다.

from django import forms
from .models import YourModel

class YourModelForm(forms.ModelForm):
    class Meta:
        model = YourModel
        fields = ['field1', 'field2', 'field3']  # 업데이트할 모델 필드를 여기에 나열

5. 템플릿 설정

각 뷰에 맞는 템플릿을 작성합니다.

yourmodel_detail.html

<p>{{ object.field1 }}</p>
<p>{{ object.field2 }}</p>
<p>{{ object.field3 }}</p>
<a href="{% url 'update-by-unique-field' object.unique_field %}">Edit</a>
<a href="{% url 'delete-by-unique-field' object.unique_field %}">Delete</a>

yourmodel_form.html

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Update</button>
</form>

yourmodel_confirm_delete.html

<form method="post">
    {% csrf_token %}
    <p>Are you sure you want to delete "{{ object }}"?</p>
    <button type="submit">Yes, delete</button>
</form>


전체 흐름 설명

  1. URL 패턴 설정: URL 경로에서 unique_field 값을 받아 각 뷰(DetailView, UpdateView, DeleteView)와 연결합니다.
  2. 뷰 정의: 기본적으로 id 필드를 사용하여 객체를 식별하지만, 여기서는 get_object 메서드를 오버라이드하여 unique_field 값으로 객체를 가져옵니다.
  3. 폼 정의: 모델 폼을 정의하여 업데이트할 필드를 지정합니다.
  4. 템플릿 작성: 각 뷰에 맞는 HTML 템플릿을 작성합니다.

이 설정을 통해 사용자는 특정 필드 값을 기준으로 객체를 찾아 업데이트, 상세 조회, 삭제할 수 있으며, 기본적으로 id를 사용하여 객체를 식별하는 제네릭 뷰의 동작을 원하는 필드로 변경할 수 있습니다.

장고 리스트