장고 사용자 문의 기능 만들기

소요 시간: 10분

사용자 문의 페이지를 만든 이유는 애플 앱 제작 가이드라인에서 필수 사항이기 때문이다. 이 기능은 사용자들이 궁금한 점이나 요청사항을 작성할 수 있는 공간을 제공하여, 사용자와 관리자가 소통할 수 있는 중요한 요소다.


사용자 문의 모델 만들기

먼저, 사용자가 남길 수 있는 문의 사항을 저장할 Inquiry 모델을 만들었다. 이 모델은 문의 제목, 내용, 작성자 정보를 포함해야 했다. 아래와 같은 코드를 작성했다:

from django.db import models
from django.contrib.auth.models import User

class Inquiry(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    subject = models.CharField(max_length=200)
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.subject

모델을 정의하는 과정이 즐거웠다. 각 문의가 언제 작성되었는지를 기록하기 위해 created_at 필드도 추가했다.

사용자 문의 모델 확장하기


문의 작성 폼 만들기

그 다음으로, 사용자가 문의를 작성할 수 있는 폼을 정의했다. 장고의 ModelForm을 이용해 InquiryForm 클래스를 만들었다. 사용자가 제목과 내용을 입력할 수 있게 했다:

from django import forms
from .models import Inquiry

class InquiryForm(forms.ModelForm):
    class Meta:
        model = Inquiry
        fields = ['subject', 'message']

이 폼 덕분에 사용자는 간편하게 문의 사항을 제출할 수 있게 되었다.


클래스 기반 뷰 설정하기

이제 사용자 문의를 처리할 뷰를 설정했다. 장고의 클래스 기반 뷰(Class-Based Views)를 활용해 InquiryCreateView를 만들었다. 이 뷰는 사용자가 입력한 문의를 데이터베이스에 저장하는 역할을 한다. 로그인한 사용자만 접근할 수 있도록 LoginRequiredMixin을 사용했다.

from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
from .models import Inquiry
from .forms import InquiryForm

class InquiryCreateView(LoginRequiredMixin, CreateView):
    model = Inquiry
    form_class = InquiryForm
    template_name = 'helps/inquiry_form.html'
    success_url = reverse_lazy('inquiry_success')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)

클래스를 정의하면서 코드의 재사용성과 가독성이 높아졌다. 특히 form_valid 메서드를 통해 현재 로그인한 사용자의 정보를 문의와 연결하는 부분이 뿌듯했다.


답변 모델 생성

사용자의 문의에 대한 답변을 저장하기 위해 Response 모델을 추가했다. 이 모델은 각 문의와 연결되어 있다. 답변 내용 및 작성자 정보를 포함한다:

class Response(models.Model):
    inquiry = models.ForeignKey(Inquiry, on_delete=models.CASCADE, related_name='responses')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Response to {self.inquiry.subject} by {self.user.username}"

여기서 related_name 속성을 사용해 문의와 답변 간의 관계를 쉽게 조회할 수 있도록 했다.


답변 폼 생성

이제 관리자가 문의에 답변할 수 있도록 ResponseForm을 만들어야 했다. 이 폼은 답변 내용을 입력할 수 있게 해준다:

from .models import Response

class ResponseForm(forms.ModelForm):
    class Meta:
        model = Response
        fields = ['message']


문의 상세보기 뷰 추가

사용자가 작성한 문의와 그에 대한 답변을 확인할 수 있도록 InquiryDetailView를 생성했다. 이 뷰는 문의 상세 정보를 보여주고, 답변을 작성할 수 있는 폼을 포함한다:

from django.views.generic import DetailView

class InquiryDetailView(LoginRequiredMixin, DetailView):
    model = Inquiry
    template_name = 'helps/inquiry_detail.html'
    context_object_name = 'inquiry'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['response_form'] = ResponseForm()
        context['responses'] = self.object.responses.all()
        return context

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        form = ResponseForm(request.POST)
        if form.is_valid():
            response = form.save(commit=False)
            response.inquiry = self.object
            response.user = request.user
            response.save()
            return redirect('inquiry_detail', pk=self.object.pk)
        return self.get(request, *args, **kwargs)

이 뷰 덕분에 사용자는 자신의 문의에 대한 답변을 쉽게 확인하고 추가할 수 있게 되었다.


URL 설정

각 뷰에 대한 URL 패턴을 설정했다. helps/urls.py 파일에 다음과 같이 추가했다:

from django.urls import path
from .views import InquiryCreateView, InquirySuccessView, InquiryDetailView

urlpatterns = [
    path('inquiry/', InquiryCreateView.as_view(), name='inquiry_form'),
    path('inquiry/success/', InquirySuccessView.as_view(), name='inquiry_success'),
    path('inquiry/<int:pk>/', InquiryDetailView.as_view(), name='inquiry_detail'),
]


템플릿 작성

마지막으로, 사용자 문의 및 답변 기능을 위한 템플릿을 작성했다. 문의 작성 페이지(inquiry_form.html)와 문의 상세보기 페이지(inquiry_detail.html)를 만들어 사용자 인터페이스를 구현했다.

문의 작성 페이지 (inquiry_form.html):

<h2>문의하기</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">문의 보내기</button>
</form>

문의 상세보기 페이지 (inquiry_detail.html):

<h2>{{ inquiry.subject }}</h2>
<p><strong>문의 내용:</strong> {{ inquiry.message }}</p>
<p><strong>작성자:</strong> {{ inquiry.user.username }}</p>
<p><strong>작성일:</strong> {{ inquiry.created_at }}</p>

<h3>답변:</h3>
{% for response in inquiry.responses.all %}
    <div>
        <strong>{{ response.user.username }}</strong> ({{ response.created_at }}):
        <p>{{ response.message }}</p>
    </div>
{% empty %}
    <p>아직 답변이 없습니다.</p>
{% endfor %}

<h3>답변 작성하기:</h3>
<form method="post">
    {% csrf_token %}
    {{ response_form.as_p }}
    <button type="submit">답변하기</button>
</form>


마이그레이션 및 테스트

모든 준비가 끝난 후, 데이터베이스에 새로운 모델을 반영하기 위해 마이그레이션을 수행했다:

python manage.py makemigrations
python manage.py migrate

이제 포럼 사이트에 사용자가 문의를 작성하고, 관리자가 그에 대한 답변을 추가할 수 있는 기능이 완성되었다. 사용자가 자신의 질문에 대한 답변을 쉽게 받을 수 있는 환경이 조성되었다.

이렇게 멋진 기능을 추가하며, 사용자와의 소통을 더 원활하게 할 수 있어서 기쁘다. 다음에는 더 많은 기능을 추가하고, 사이트를 더욱 발전시킬 방법을 고민할 예정이다.

장고 리스트