icon picker
장고 폼

한 가지만 더 하면 웹사이트가 완성됩니다.
바로 블로그 글을 추가하거나 수정하는 멋진 기능을 추가하는 것이죠.
폼을 하나 만들어서 Post 모델에 적용해봅시다.
장고의 모든 중요한 부분과 마찬가지로, 폼도 폼만의 forms.py라는 파일을 만들어요.
우리는 이 이름으로 blog 디렉토리 안에 파일을 만들 거에요.
blog
└── forms.py
이제 이 파일을 열고 아래 코드를 작성해보세요!
blog/forms.py
from django import forms

from .models import Post

class PostForm(forms.ModelForm):

class Meta:
model = Post
fields = ('title', 'text',)

위 코드를 보시면, ​Forms를 불러오고, 그 다음 Postmodels.py에서 불러오는 것입니다. ​PostForm 은 우리가 만들 폼의 이름이에요. 그리고 장고에다 이 폼이 ModelForm이라는 것을 알려줘야해요. ​forms.ModelForm로 ModelForm이라는 것을 장고에 알려줍니다!
class Meta가 나오는데요, 이 구문은 이 폼을 만들기 위해서 어떤 model이 쓰여야 하는지 장고에 알려주는 구문입니다. (model = Post)
마지막으로, 이 폼에 필드를 넣으면 완성되겠죠. 이번 폼에서는 titletext만 보여지게 해 봅시다. - author는 현재 로그인 하고 있는 사람이 될 것이고 (바로 당신이요!) 그리고 created_date는 글이 등록되는 시간이 될 것입니다. (예를 들어, 코드 상에서요), 됐죠?
마쳤습니다! 이제 에서 이 폼을 사용해 템플릿에서 보여주기만 하면 되네요.
다음에는 링크, URL, 뷰 그리고 템플릿을 만들 거에요.

폼과 페이지 링크

blog/templates/blog/base.html 파일을 열어봅시다. page-header 라는 div class에 링크를 하나 추가할 거에요.
blog/templates/blog/base.html
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
이렇게 보이실 거에요!
blog/templates/blog/base.html
{% load static %}
<html>
<head>
<title>Django Girls blog</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link href='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="{% static 'css/blog.css' %}">
</head>
<body>
<div class="page-header">
<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
<h1><a href="/">Django Girls Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</body>
</html>
앗, NoReverseMatch이라는 에러가 나타나죠? 걱정마세요 :)

URL

이제 blog/urls.py를 열고 아래 구문을 추가할게요!
blog/urls.py
path('post/new', views.post_new, name='post_new'),

urls.py전체 코드는 아래와 같습니다.
blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
]
앗, 브라우저에 사이트를 다시 불러오면 AttributeError가 보이는데요? 왜냐하면, 아직 post_new뷰를 구현하지 않았기 때문이에요! 이제 하나 더 추가해보죠.

post_new view

blog/views.py파일을 열어서 from줄에 아래와 같은 코드를 추가합니다.
blog/views.py
from .forms import PostForm

def post_new(request):
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
Post 폼을 추가하기 위해 PostForm() 함수를 호출하도록 하여 템플릿에 넘깁니다. 곧 view 로 다시 돌아와서 이 작업을 하겠지만, 지금 당장은 폼을 위한 템플릿을 먼저 빨리 만들어보도록 할게요.

템플릿

이번에는 blog/templates/blog 디렉터리 안에 post_edit.html 파일을 생성해 폼이 작동할 수 있게 만들 거에요.
먼저 폼이 보여야 합니다. 그 예로, {{ form.as_p }}로 간단히 만들 수 있어요….
위 코드를 HTML 태그로 폼을 감싸세요. <form method="POST">...</form>
Save 버튼이 필요합니다. 이것은 HTML 버튼으로 만들 수 있어요: <button type="submit">Save</button>
마지막으로 <form ...>을 열어 {% csrf_token %}를 추가하세요. 이 작업은 폼 보안을 위해 중요하답니다! 이 작업을 빼먹고 저장하면 장고는 이렇게 불평할 거에요.
CSFR Forbidden page
네, 이제 post_edit.html 파일의 HTML을 확인해볼까요??
blog/templates/blog/post_edit.html
{% extends 'blog/base.html' %}

{% block content %}
<h1>New post</h1>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
서버를 켜보고 로 들어가봅시다.
New form
근데, 타이틀과 텍스트에다 내용을 입력하는건 되지만, 저장을 하게 되면 오류가 나올겁니다.

폼 저장하기

blog/views.py를 다시 여세요. 지금 여러분이 보고 있는 post_new뷰는 아래와 같을 거에요.
blog/views.py
def post_new(request):
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
폼을 제출할 때, 같은 뷰를 불러옵니다. 이때 request에는 우리가 입력했던 데이터들을 가지고 있는데, request.POST가 이 데이터를 가지고 있습니다. (POST는 글 데이터를 "등록하는(posting)"하는 것을 의미합니다. 블로그 "글"을 의미하는 "post"와 관련이 없어요) HTML에서 <form>정의에 method="POST"라는 속성이 있던 것이 기억나나요? 이렇게 POST로 넘겨진 폼 필드의 값들은 이제 request.POST에 저장됩니다. ​POST로 된 값을 다른 거로 바꾸면 안 돼요. ​method 속성의 값으로 넣을 수 있는 유효한 값 중에 GET같은 것도 있지만, post와 어떤 차이점이 있는지 등에 대해서 다루기에는 너무 길어질 것 같아 생략할게요)
이제 view 에서 두 상황으로 나누어 처리해볼게요.
첫 번째: 처음 페이지에 접속했을 때입니다. 당연히 우리가 새 글을 쓸 수 있게 폼이 비어있어야겠죠.
두 번째: 폼에 입력된 데이터를 view 페이지로 가지고 올 때입니다. 여기서 조건문을 추가시켜야 해요. (if를 사용하세요)
blog/views.py
if request.method == "POST":
[...]
else:
form = PostForm()

[...] 이 부분을 이제 추가해볼 것입니다! 만약 methodPOST라면, 폼에서 받은 데이터를 PostForm으로 넘겨줘야겠죠? 이렇게 코드를 작성하면 됩니다.
blog/views.py
form = PostForm(request.POST)
참 쉽죠! 다음에는 폼에 들어있는 값들이 올바른지를 확인해야합니다.(모든 필드에는 값이 있어야하고 잘못된 값이 있다면 저장하면 되지 않아야해요) 이를 위해 form.is_valid()을 사용할거에요.
폼에 입력된 값이 올바른지 확인한 다음, 저장되는거죠!
blog/views.py
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_date = timezone.now()
post.save()
일반적으로 이 작업을 두 단계로 나눌 수 있어요. ​form.save()로 폼을 저장하는 작업과 작성자를 추가하는 작업입니다. (PostForm에는 작성자(author) 필드가 없지만, 필드 값이 필요하죠!) ​commit=False란 넘겨진 데이터를 바로 Post 모델에 저장하지는 말라는 뜻입니다. 왜냐하면, 작성자를 추가한 다음 저장해야 하니까요. 대부분의 경우에는 commit=False를 쓰지 않고 바로 form.save()를 사용해서 저장해요. 다만 여기서는 작성자 정보를 추가하고 저장해야 하므로 commit=False를 사용하는 거예요. ​post.save()는 변경사항(작성자 정보를 포함)을 유지할 것이고 새 블로그 글이 만들어질 거에요!
끝으로, 새 블로그 글을 작성한 다음에 post_detail페이지로 이동할 수 있으면 좋겠죠? 이 작업을 하려면 한 가지를 더 불러와야 해요. 위에 적어줍시다!
from django.shortcuts import redirect
그리고 새로 작성한 글을 볼 수 있도록 post_detail페이지로 가라고 수정합시다.
blog/views.py
return redirect('post_detail', pk=post.pk)
post_detail은 우리가 이동해야 할 뷰의 이름이에요 post_detail 뷰pk변수가 필요한 거 기억하고 있겠죠? pk=post.pk를 사용해서 뷰에게 값을 넘겨줄 거에요. 여기서 post는 새로 생성한 블로그 글이에요.
blog/views.py
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.published_date = timezone.now()
post.save()
return redirect('post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
views.pypost_new의 전체 코드입니다! 서버를 실행해보세요! 게시글이 이제 성공적으로 저장될 것입니다 :)
image.png
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.