샘플 - Feedback 예제
간단한 샘플 App으로서 지금까지 설명한 Feedback App에 대해 보다 자세히 알아보자. Feedback App은 간단한 코멘트를 입력받고, 편집하고, 전체 리스트를 보여주는 간단한 App이다. 아래 그림은 전체 리스트 (/feedback/list) 보기과 편집 (/feedback/edit/2) 폼에 대한 샘플 화면이다.
1. 뷰 (View)
View (feedback/views.py) 파일에 리스트(list), 피드백 추가(create), 피드백 편집(edit) 등 3개의 함수 를 작성하였다.
create 함수는 이전 아티클에서 이미 설명하였으므로 list와 edit을 간단히 설명하면, list 는 모든 Feedback 데이타를 가져와 feedbacklist.html 템플릿에 전달하여 전체 피드백 리스트를 작성한다. edit 는 id 를 URL에서 전달받아 (/feedback/edit/2 와 같이) 해당 id를 갖는 Feedback 데이타 하나를 feedback.html 템플릿에서 수정하게 한다.
from django.shortcuts import render, redirect from .models import * from .forms import FeedbackForm def list(request): feedbacks = Feedback.objects.all() return render(request, 'feedbacklist.html', {'feedbacks': feedbacks}) def create(request): if request.method=='POST': form = FeedbackForm(request.POST) if form.is_valid(): form.save() return redirect('/feedback/list') else: form = FeedbackForm() return render(request, 'feedback.html', {'form': form}) def edit(request, id): fb = Feedback.objects.get(pk=id) if request.method=='POST': form = FeedbackForm(request.POST, instance=fb) if form.is_valid(): form.save() return redirect('/feedback/list') else: form = FeedbackForm(instance=fb) return render(request, 'feedback.html', {'form': form})
특히 edit() 함수에서 하나의 Feedback 객체를 Feedback.objects.get() 을 통해 가져온 후, 이를 FeedbackForm(instance=fb) 폼 생성자에 "instance=" 을 써서 전달하고 있음에 유의하자 (주: edit() 함수의 else 부분). 이렇게 하면 해당 Feedback 객체의 필드값들이 채워진 FeedbackForm 객체가 생성된다.
또한, 편집 내용이 저장되어 POST로 전달될 때, FeedbackForm(request.POST, instance=fb) 와 같이 표현되고 있는데, 이는 save()시 해당 Feedback객체(fb)가 request.POST 데이타로 갱신되게 한다 (주: edit() 함수의 if 블럭).
2. 템플릿
Feedback 템플릿들은 ./feedback/templates 폴더에 있으며, 기본 템플릿 (./templates/base.html) 을 확장한 템플릿들이다.
우선 기본 템플릿인 base.html의 내용은 다음과 같다. 이 기본 템플릿에는 2개의 block (title과 content block)을 사용하였다.
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>My Web</title> <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}"> </head> <body> <div class="container"> <h2> My Web </h2> </div> <div class="container"> {% block title %} {% endblock title %} </div> <div class="container"> {% block content %} {% endblock content %} </div> </body> </html>
다음은 feedback.html의 내용으로 create와 edit 함수에 의해 사용되는 템플릿이다.
{% extends "base.html" %} {% block title %} <h3> Your Feedback </h3> {% endblock title %} {% block content %} <p> <a href="{% url 'list' %}">Goto List</a> </p> <div> <form method="POST"> {% csrf_token %} <table class="table"> {{ form.as_table }} </table> <button type="submit">저장</button> </form> </div> {% endblock content %}
다음은 feedbacklist.html의 내용으로 list 함수에 의해 사용되는 템플릿이다.
{% extends "base.html" %} {% load staticfiles %} {% block title %} <h3> <img src="{% static 'images/note.jpg' %}" style="width:50px" /> Feedback List </h3> {% endblock title %} {% block content %} <p> <a href="{% url 'create' %}">+ Create New</a> </p> <table class="table"> <tr><th>Id</th><th>Name</th><th>Email</th><th>Comment</th></tr> {% for item in feedbacks %} <tr> <td> <a href="{% url 'edit' id=item.id %}">{{ item.id }}</a> </td> <td>{{ item.name }}</td> <td>{{ item.email }}</td> <td>{{ item.comment }}</td> </tr> {% endfor %} </table> {% endblock content %}
특히 위 템플릿에서 ID 컬럼을 보면, HTML a 태그를 사용하여 ID를 누르면 편집(edit) 기능을 호출하게 하였다. a 태그의 href 값을 보면, url 이름이 edit 으로 되어 있으며, 여기에 해당 ROW의 id 값을 추가로 설정하고 있다. 이 태그 표현식은 템플릿 엔진에 의해 예를 들어 "/feedback/edit/2" 과 같이 해석된다.
3. App URL 매핑
뷰(View)의 각 함수들에 상응하는 URL 매핑은 ./feedback/urls.py 에 아래와 같이 정의하였다. 여기서 각 url 마다 name을 정의하였는데, 이 name은 위 템플릿의 {% url %} 태그에서 사용되고 있다.
from django.conf.urls import url from feedback import views urlpatterns = [ url(r'^list', views.list, name='list'), url(r'^create', views.create, name='create'), url(r'^edit/(?P\d+)/$', views.edit, name='edit'), ]
그리고 이미 설명되었지만, Django 프로젝트의 urls.py 파일 안에는 feedback App에 대한 URL 매핑이 다음과 같이 설정되어 있다.
urlpatterns = [ #... 다른 매핑 생략... url(r'^feedback/', include('feedback.urls')), ]