[장고] id가 아닌 특정 필드로 제네릭 뷰 사용하기
Django에서 제네릭 뷰(CreateView, DetailView, UpdateView, DeleteView)는 기본적으로 id를 사용하여 객체를 식별합니다. 또한 특정 필드 값을 기준으로 사용하도록 설정할 수 있습니다.
장고 제네릭 뷰
장고(Django)에서 제네릭(Generic) 뷰는 웹 애플리케이션의 공통 패턴을 간소화하고 중복 코드를 줄이기 위해 제공되는 클래스 기반 뷰입니다. 제네릭 뷰를 사용하면 CRUD(Create, Read, Update, Delete) 작업을 쉽게 처리할 수 있습니다.
제네릭 뷰의 종류
- ListView: 데이터베이스의 객체 목록을 보여주는 뷰입니다.
- DetailView: 단일 객체의 상세 정보를 보여주는 뷰입니다.
- CreateView: 새로운 객체를 생성하는 뷰입니다.
- UpdateView: 기존 객체를 수정하는 뷰입니다.
- 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는 이를 통해 데이터베이스에서 해당 객체를 찾습니다.
제네릭 뷰의 동작 원리
- URL에서 ID 추출: URL 패턴에서 <int:pk>/와 같은 구문을 사용하여 객체의 ID를 추출합니다.
- 객체 조회: DetailView는 전달된 ID를 사용하여 데이터베이스에서 해당 객체를 조회합니다.
- 컨텍스트에 추가: 조회된 객체는 컨텍스트에 추가되어 템플릿에서 사용할 수 있습니다.
- 템플릿 렌더링: 지정된 템플릿 파일을 렌더링하여 사용자에게 응답합니다.
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>
전체 흐름 설명
- URL 패턴 설정: URL 경로에서 unique_field 값을 받아 각 뷰(DetailView, UpdateView, DeleteView)와 연결합니다.
- 뷰 정의: 기본적으로 id 필드를 사용하여 객체를 식별하지만, 여기서는 get_object 메서드를 오버라이드하여 unique_field 값으로 객체를 가져옵니다.
- 폼 정의: 모델 폼을 정의하여 업데이트할 필드를 지정합니다.
- 템플릿 작성: 각 뷰에 맞는 HTML 템플릿을 작성합니다.
이 설정을 통해 사용자는 특정 필드 값을 기준으로 객체를 찾아 업데이트, 상세 조회, 삭제할 수 있으며, 기본적으로 id를 사용하여 객체를 식별하는 제네릭 뷰의 동작을 원하는 필드로 변경할 수 있습니다.