라이브러리는 도서관 아닌가요

[Django 7] django db, form 연습 ( model 사용 예제 ) 본문

Django/Django 프로젝트

[Django 7] django db, form 연습 ( model 사용 예제 )

veryhi 2021. 10. 7. 16:23

 

이번에는 models.py와 forms.py를 이용한 db 및 form 연습

 

 

우선 Django에서 form은 웹 사용자가 데이터를 입력했을 때 이를 처리해주는 역할을 한다.

 

그리고 입력된 데이터가 유효한지를 판단해서 db model과 연동할 수 있도록 돕는다.

 

 

 

 

 

이전에서 다루던 프로젝트와는 다르게 별개의 프로젝트를 만들어 그 사용법을 살펴보도록 하자.

 

아래와 같이 입력해서 프로젝트(form_practice) 및 sub abb(main)을 생성한다.

 

 

 

 

 

그 다음은 역시, settings.py의 최소한의 기본 설정을 해준다. 생성한 App을 인식하기 위해 INSTALLED_APPS에 등록.

'main.apps.MainConfig'

 

 

 

 

 

간단한 templates도 생성할 것이므로 아래와 같이 추가.

'DIRS': [os.path.join(BASE_DIR, "templates")],

 

 

 

 

 

그 다음 최상단의 form_practice 경로에서 templates 디렉터리를 생성한다.

 

templates에 main 디렉터리를 생성하고, home.html을 생성한다. 아직은 html의 내용이 중요치 않다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>form handling</h1>
</body>
</html>

 

 

 

 

 

그리고 main app 내에 urls.py 파일을 만들어 다음과 같이 url pattern을 지정해주자.

from django.urls import path
from . import views

# app별 관리를 위해 이름 지정
app_name = 'main'

urlpatterns=[
    path('', views.home, name='home'),
]

 

 

 

 

 

그리고  form_practice/form_practice/urls.py 경로에도 아래와 같이 app 관련 url을 추가해주자.

 

 

 

 

 

자 그리고 현재까지의 상황을 테스트해보기 위해 views에 실질적인 함수를 추가해서 확인하자

 

 

 

 

 

127.0.0.1:8000에 들어가면 당연히 에러가 난다.

Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/

 

 

 

 

 

우리는 도메인 정책에 따라 127.0.0.1:8000/main으로 접속해야 한다.

음, 잘 됐다.

 

그러면 이제 이 상태에서 form을 설계(?)해보자.

 

앞서 말했다시피 form은 사용자의 입력을 받는다고 했다. 그러면 이 받은 입력은 어떻게 처리할까?

 

 

 

 

 

당연히 db model을 사용해서 db.sqlite3에 저장하여(writing) 쓴다.

 

물론 db를 다루지 않고 입력을 처리할 수도 있겠지만,

 

일반적으로 db를 조작하는 입력은 form을 거쳐서 유효성을 검사한다.

 

 

 

 

 

그러면 form을 작성하기 이전에 models.py에 데이터 모델을 만들어야 하는 것이다. 아래와 같이 입력하자.

from django.db import models

# Create your models here.
class make_content(models.Model):
    content = models.TextField(verbose_name='content')
    
    def __str__(self):
        return self.content

지금은 어렵게 생각할 게 없다.

 

Content라는 model class를 만들어서 content라는 속성을 조작한다.

 

content는 TextField이므로 text의 입력을 받아 저장할 수 있다, 라고만 알아두자.

 

 

 

 

 

당연히 model을 설계했을 때는 마이그레이션(migration)을 해주어야 한다.

 

db에 실제 테이블이 생성되어야 하니까.

python manage.py makemigrations main
python manage.py migrate

( TMI: 대게 form이랑 view까지의 설계를 마친 후 하는 것이 좋을 때가 많다.

 

둘을 구현하다가 models.py를 수정하는 경우가 더러 있기 때문이다.

 

model은 한 번 migration 하고 난 뒤에 수정하기가 껄끄럽다. )

 

 

 

 

 

다음은 forms.py를 생성하고 아래의 코드를 입력하자. (지금은 연습이 목적이므로 폼이 좀? 간단하다.)

from django import forms
from .models import Content

class ContentForm(forms.ModelForm):
    def __init(self, *args, **kwargs):
        super(ContentForm, self).__init__(*args, **kwargs)
        self.fields['content'].widget.attrs.update({
            'class': 'form-control',
            'autofocus': True
        })

    class Meta:
        model = Content
        fields = ['content']

일반적으로 많이 사용하는 django의 폼 형태이다.

 

django의 widget 기능을 사용해서 해당 form이 'form-control'을 받게 한다.

 

(입력이 안되면 제출(submit)이 되지 않게 경고문을 띄운다.)

 

그리고 페이지를 열었을 때, 'autofocus'되도록 한다.

 

Meta class를 통해 명시적으로 model과 fields를 지정해주었다.

 

 

 

 

 

그 다음 form에 맞춘 템플릿(외관)을 구현하면 된다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>form handling</h1>
    <form method="post">
        {% csrf_token %}
        <div>{{form.content}}</div>
        <button type="submit">save</button>
    </form>

</body>
</html>

여기서 중요한 몇가지를 짚어보자면,

 

첫 번째로 form은 'post' 형식으로 입력을 받게끔 method를 지정해준다.

 

→ 사이트 간의 요청 위조 공격에 대비한 보안상의 이유로 post를 사용한다.

 

다만 post 요청을 항상 form으로 받을 필요는 없다. 더불어 post 요청만 form으로 처리할 수 있는 것은 아니다.(get 가능)

 

 

 

두 번째로 {% csrf_token %}이라는 django의 키워드가 들어가 있는데 이것 또한 보안의 목적이다.

 

→ 사용자가 post 방식으로 입력을 할 때만 token을 발급하고 체크한다.

 

 

 

세 번째로 {{ form.content }}인데, 장고는 db와 template을 조작할 때 키워드 {% 내용 %} or {{ 내용 }}을 사용한다.

 

→ 템플릿 태그라고도 하는데, view를 통해 db의 데이터를 가져와 html에 반영한다. (렌더링한다.)

 

앞으로 하나씩 살펴볼 예정이다.

 

여담으로 submit을 담당하는 <button>은 form 태그 영역 밖으로 벗어나면 효력이 사라진다.

 

 

 

 

 

다음으로 정말 중요한 작업이 남아있는데, 바로 view에 함수를 정의하는 것이다.(CBV는 차후에 여유롭게 다루겠습니다.)

 

그전에, view에서 사용할 템플릿을 하나만 더 구현하고 넘어가도록 하자.

 

 

 

 

 

templates/main/ 경로result.html을 생성하고 아래의 코드를 넣는다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% if result_list %}
    {% for result in result_list %}
    <p>{{result.content}}</p>
    {% endfor %}
    {% endif %}
</body>
</html>

home에서 입력을 받아 db에 저장한 후 result.html에 연결되어 결과를 보여주도록 하기 위한 코드이다.

 

 

 

 

 

이제 대망의 view를 살펴보도록 하자. 아래에 main/views.py에 들어갈 아래의 코드를 입력.

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import ContentForm
from.models import Content

# Create your views here.
def home(request):
    if request.method == "POST": #2 요청이 POST 형식일 때
        form = ContentForm(request.POST)
        if form.is_valid():
            content_form = form.save(commit=False) # 바로 저장하는 것을 방지
            content_form.save()
            return redirect('result/')
        else:
            messages.error(request, "error")
            return redirect('main/home.html')

    else: #1 home.html 페이지에 접속하면 여기가 먼저 실행된다.
        form = ContentForm()
        context = {
            'form': form
        }
        return render(request, 'main/home.html', context)


def result(request):
    result_list = Content.objects.all()
    context = {
        'result_list' : result_list
    }
    return render(request, 'main/result.html', context)

빨갛게 주석처리 된 순서의 흐름대로 살펴보자.

 

우리가 처음 home.html에 접속하면,

 

post로 요청을 보낼 수 없으므로(당연하다),

 

ContentForm(forms.py에 구현된 것)을 불러와 form이라는 변수에 저장시키고,

 

그것을 렌더링해서 main/home.html을 다시금 띄워준다.

 

우리는 단지 페이지에 들어갔을 뿐인데 django는 혼자 시작부터 바쁘다.

 

다시 말해, 입력 받기 위해 form 형식을 사전에 깔아놓는 것이다.

 

context = { 'form' : form } 구문은 장고가 페이지를 바쁘게 렌더링할 때,

 

html 문서에 같이 실어보내기 위한 데이터 양식들이다.

 

쉽게 말해 db의 내용들 혹은 form 양식이다.

 

실제로 아랫쪽 함수 def result에서 살펴보면

 

우리가 db에 저장한 내용을 result_list에 전부 불러온 다음 그것을 context 양식에 맞춰 담고 렌더링 해준다.

 

(나중에 result.html에 들어가면 이 데이터들을 받아서 html에 띄워주는 것을 볼 수 있다.

 

위의 result.html에 적힌 구문을 살펴보고 감을 잡도록 하자.)

 

 

 

 

 

그러면 서버를 실행시켜 잘 동작하는지 살펴보자.

 

 

 

 

 

입력 후 save하면, 앞에 입력해 놓았던 데이터와 함께 결과를 보여준다.

 

 

 

 

 

sqlite3를 사용해서 입력된 데이터를 살펴보자.

 

 

 

 

 

table 이름이 main_content로 지어져 있는데 이는 django의 default 네이밍 센스이다... (main 앱의 content 테이블)

 

models.py에서 모델을 작성할 때, 따로 db table 이름을 지정해줄 수 있으니 참고하도록 하자.

    class Meta:
        db_table = 'content'
        verbose_name = 'Content'
        verbose_name_plural = 'Content'

(마이그레이션 이전에 위 내용을 추가해주면 된다. 이번에는 단지 연습을 위한 것이었으므로 굳이 넣진 않았다.)

 

 

 

DB model과 form을 이용하여 데이터 입력 및 저장, 그리고 템플릿에 띄우기 완료

Comments