본문 바로가기

BACK-END/Django

[Django][장고걸스][ubuntu] Django Form

Form을 이용하면 글을 Create, Update, Delete가 가능하다.

Create와 Update를 해보자.

 

 

Form 위치

 

blog (StartApp)
└─── forms.py

 


 

1. CREATE [폼 추가하기]

 


 

Form 작성

 

장고에서 제공해주는 Form인 ModelForm을 이용했다.

 

blog/forms.py

from django import forms
from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'text',)

 

Meta는 이 Form을 만들기 위해 어떤 model이 쓰여야 하는지 장고에 알려주는 구문이다.

fields에는 보여지게 할 필드를 넣는다.

(author필드, created_date필드, published_date필드는 유저가 직접 입력하는 부분이 아니기 때문에 넣지 않는다.)

 


 

form과 페이지 링크

 

base.html에서 플러스 버튼을 누르면 새 글을 추가할 수 있게 해보자.

 


 

blog/templates/base.html

<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>

 

부트스트랩 테마에 있는 glyphicon 클래스로 더하기 기호가 보이게 된다.

 


 

blog/urls.py

path('post/new', views.post_new, name='post_new'),

 


 

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})

 

forms.py에서 만든 폼을 불러온다.

 

HTML에서 <form>정의에 method="POST"라는 속성이 있었다.

따라서 POST로 넘겨진 폼 필드의 값들은 request.POST에 저장된다.

 

view는 두 상황으로 나누어 처리할 수 있다.

 

1. 처음 페이지에 접속했을 때

우리가 새 글을 쓸 수 있게 폼이 비어있어야한다.

 

2. 폼에 입력된 데이터를 view 페이지로 가지고 올 때

method가 POST라면 폼에서 받은 데이터를 PostForm으로 넘겨주면 된다.

그러곤 바로 저장하는 게 아니다. 아래 부분을 보자.

 

        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)

 

먼저, is_valid()로 폼에 입력된 값이 올바른지 확인해야 한다.

 

다음 작업은 일반적으로 두 단계로 나눌 수 있다.

 

1. form.save()로 폼을 저장하는 작업

2. author 필드, published_date 필드를 추가하는 작업

 

PostForm에는 author필드, published_date 필드가 없다.

따라서 commit=False로 데이터를 바로 Post 모델에 저장하지 않게 한다.

그리고 빈 필드를 채운다.  이제 저장한다.

 

redirect를 이용하면 지정한 페이지로 이동한다.

 


 

blog/templates/post_edit.html

{% extends '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 %}

 

1. {{ forms.as_p }}로 폼이 보이게 한다.

2. HTML 태그로 폼을 감싼다. <form method="POST"> ... </form>

3. HTML로 save 버튼을 만든다.

4. 마지막으로 <form ...>을 열어서 {% csrf_token %}을 추가한다. (폼 보안을 위해서)

 


 

2. UPDATE [폼 수정하기]

 


 

디데일 페이지에서 수정하기 버튼을 눌러 글을 수정할 수 있게 하자.

 

blog/templates/post_detail.html

<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>

 

post_detail.html에 위 코드를 추가한다.

 


 

blog/urls.py

  path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),

 

ursl.py에 위 코드를 추가한다.

 


 

blog/views.py

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    
    if request.method == "POST":
        form = PostForm(instance=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(instance=post)
        
    return render(request, 'blog/post_edit.html', {'form': form})

 

post_new 함수와 비슷해 보인다. 하지만 완전히 같지는 않다.

 

다른 점

 

1. pk를 매개변수로 받는다.

2. get_object_or_404를 호출하여 수정하고자 하는 글의 Post 모델을 instance로 가져온다.

 

이렇게 가져온 데이터를 폼을 만들 때와 폼을 저장할 때 사용하게 된다.

 


 

결과

 

 

CREATE

 

 

DETAIL

 

 

UPDATE

 


보안

 

아래 조건문을 추가하면 로그인하지 않은 유저는 글 추가 버튼이 보이지 않는다.

 

blog/templates/base.html

{% if user.is_authenticated %}
    <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
{% endif %}