django-6. 폼(Form)
January 28, 2018
[Post:5.뷰] 에서 생성된 post를 보여주는 화면을 생성했다. 이제 화면에서도 post를 생성할 수 있게 만들자. django는 다른 어떤 프레임워크보다 편리한 폼제어를 할 수 있다. 개발자가 따로 어떠한 일을 하지 않아도 아래와 같은일을 알아서 해준다.
- 데이터 준비 및 재구성 후 랜더링 준비
- 데이터에 대한 html 양식 구성
- 클라이언트로 부터 제출 된 양식 및 데이터 수신 및 처리
django Docs: working with forms
템플릿 생성 post_edit.html
{{form}} 인경우 그냥 랜더링 되지만, 옵션을 선택할 수 있음. {{ form.as_table }} table 셀로 wrap 됨. {{ form.as_p}} p 태그로 wrap {{ form.as_ul }} li 태그로 wrap
{% extends 'simple.html' %}
{% load staticfiles %}
{% block simpleContents %}
<link rel="stylesheet" href="{% static 'css/post.css' %}">
<p class="bar_title hidden">{{post.title}}(edit)</p>
<div class="post_box row" style="margin-top:50px;">
<form method="POST" class="post-form" enctype="multipart/form-data">
{% csrf_token %}
{{form}}
<button type="submit" class="saveBtn btn btn-primary col-sm-12">Save</button >
</form>
</div>
{% endblock %}
수동으로 랜더링도 가능하다.
<form
{% /csrf_token %}
<div class="form-group">
{{form.title.label_tag}}
<input type="text" class="form-control" id="{{ form.title.id_for_label }}" aria-describedby="title" placeholder="title">
</div>
<div class="form-group">
<label for="{{ form.content.id_for_label }}">내용:</label>
<input type="text" class="form-control" id="{{ form.content.id_for_label }}" aria-describedby="contents" placeholder="contents">
</div>
<button type="submit" class="saveBtn btn btn-primary col-sm-12">Save</button >
</form>
urls.py 에 edit url을 추가 한다.
url(r'^edit/(?P<\pk>\d+)/$', views.post_edit, name='post_edit'),
forms.py
from django import forms
from .models import Post
class PostForm(forms.Form):
title = forms.CharField(label='제목', max_length=100)
content = forms.CharField(label='내용')
view.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from .models import Post
from .forms import PostForm ## 추가
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, request.FILES, instance=post) ##추가하고자 하는 글의 Post모델 인스턴스를 가져옴
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'pages/post/post_edit.html', {'form': form, 'post':post})
위에서 보면 알 수 있듯이 정말 간단히 form 을 자동으로 랜더링 할 수 있다.
meta클래스를 이용해서 form을 만들 수도 있다. (개인적으로 이방법을 더 선호 한다.)
forms.py
from django import forms
from .models import Post
EMPTY_TITLE_ERROR = "제목을 입력하세요"
EMPTY_CONTENT_ERROR = "내용을 입력하세요"
class Meta:
model = Post
fields = ('categoryCd','title','content','published_date')
labels = {
'categoryCd' : '카테고리',
'title':'제목',
'content':'내용',
'published_date':'개시일'
}
widgets = {
'title': forms.TextInput({'class':'form-control'}),
'content': forms.Textarea({'width': '100%', 'class':'form-control'}),
'published_date' :forms.DateInput({'class':'form-control', 'type':'date'})
}
error_messages = {
'title': {'required': EMPTY_TITLE_ERROR},
'content': {'required': EMPTY_CONTENT_ERROR}
}
views.py
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, request.FILES, instance=post) ##추가하고자 하는 글의 Post모델 인스턴스를 가져옴
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'pages/post/post_edit.html', {'form': form, 'post':post , 'page_tit' : post.title+' (수정)' })
post_list.html
{% extends 'simple.html' %}
{% load staticfiles %}
{% block simpleContents %}
<link rel="stylesheet" href="{% static 'css/post.css' %}">
<p class="bar_title hidden">{{post.title}}(edit)</p>
<div class="post_box row" style="margin-top:50px;">
<form method="POST" class="post-form" enctype="multipart/form-data" style="width:100%;">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
{{field.label_tag}}
{{field}}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="saveBtn btn btn-primary col-sm-12">Save</button >
</form>
</div>
{% endblock %}
같은 방법으로 post_new을 만든다.
주의할 점은 view.py에서 new는 post를 따로 불러오지 않고, form을 불러올때 post를 주지 않아도 됨. 그리고 오늘 날짜로 setting 해줌.
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False) ##넘겨진 데이터를 바로 저장하지 말라는 뜻
post.author = request.user
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm(initial={'published_date':timezone.now()}) ## 오늘 날짜로 개시일 설정
return render(request, 'pages/post/post_edit.html', {'form': form, 'page_tit':'새로운 포스트'})