[Django] Form / ModelForm

문지은·2023년 4월 22일
1

Django 기초

목록 보기
8/14
post-thumbnail

사용자가 입력한 데이터가 우리가 원하는 데이터 형식이 맞는지에 대한 유효성 검증을 도와주는 Django Form과 ModelForm에 대해 알아보자!


⭐️ Django Form Class

  • Form은 Django의 유효성 검사 도구 중 하나로 외부의 악의적 공격 및 데이터 손상에 대한 중요한 방어 수단
  • Django는 Form과 관련한 유효성 검사를 단순화하고 자동화할 수 있는 기능을 제공하여, 개발자가 직접 작성하는 코드보다 더 안전하고 빠르게 수행하는 코드를 작성할 수 있다.
    • 개발자가 필요한 핵심 부분만 집중할 수 있도록 돕는 프레임워크의 특성

Django는 Form에 관련된 작업의 세 부분을 처리

  1. 렌더링을 위한 데이터 준비 및 재구성
  2. 데이터에 대한 HTML forms 생성
  3. 클라이언트로부터 받은 데이터 수신 및 처리

From Class 선언

  • Form Class를 선언하는 것은 Model Class를 선언하는 것과 비슷하다.
    • 비슷한 이름의 필드 타입을 많이 가지고 있다. (이름만 같을 뿐 같은 필드는 아님)
  • Model과 마찬가지로 상속을 통해 선언
    • forms 라이브러리의 Form 클래스를 상속 받음
  • 앱 폴더에 forsm.py를 생성 후 ArticleForm Class 선언
  • form에는 model field와 달리 TextField가 존재하지 않음
    • 모델의 TextField처럼 사용하려면 widgets 사용
# articles/forms.py

from django import forms

class ArticleForm(forms.Form):
     title = forms.CharField(max_length=10)
     content = forms.CharField(widget=forms.Textarea)

view 업데이트

from .forms import ArticleForm

def create(request):
    if request.method == 'POST':
        title = request.POST.get('title')
				content = request.POST.get('content')
				article = Article(title=title, content=content)
				article.save()
				return redirect('articles:detail', article.pk)
    else:
        form = ArticleForm()
		    context = {'form':form }
		    return render(request, 'articles/create.html', context)

create 템플릿 업데이트

{% extends 'base.html' %}

{% block content %}
  <h1>글작성</h1>
  <hr>

  <form action="{% url 'articles:create' %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit">
  </form>
{% endblock content %}

From rendering options

  • <label> & <input> 쌍에 대한 3가지 출력 옵션
  1. as_p()
    • 각 필드가 단락(<p> 태그)으로 감싸져서 렌더링
  2. as_ul()
    • 각 필드가 목록 항목(<ul> 태그)으로 감싸져서 렌더링
    • <ul> 태그는 직접 작성해야 함
  3. as_table()
    • 각 필드가 테이블(<tr> 태그)행으로 감싸져서 렌더링

HTML input 요소로 표현하는 방법

Form fields

  • 입력에 대한 유효성 검사 로직을 처리
  • 템플릿에서 직접 사용됨
  • 예 : forms.CharField()

Widgets

  • 웹페이지의 HTML input 요소 렌더링을 담당
    • 단순히 input 요소의 보여지는 부분을 변경하는 것으로 유효성 검증과는 관계 없음
  • Widgets은 반드시 form fields에 할당됨
  • 예 : forms.CharField(widget=forms.Textarea)
  • 다양한 built-in 위젯 확인하기

Article Model Class에 필드에 대한 정보를 작성하고 이를 Form에 맵핑하기 위해서는 Form Class에 필드를 재정의해야 하고 Model과 중복 되는 부분이 많아 번거롭다.

이러한 Form을 더 쉽게 작성할 수 있게 해주는 ModelForm에 대해 알아보자.

⭐️ Django ModelForm

ModelForm Class

  • Model을 통해 Form Class를 만들 수 있는 helper class
  • ModelForm은 Form과 똑같은 방식으로 View 함수에서 사용

ModelForm 선언

  • form 라이브러리에서 파생된 ModelForm 클래스를 상속받음
  • 정의한 ModelForm 클래스 안에 Meta 클래스를 선언
  • 어떤 모델을 기반으로 form을 작성할 것인지에 대한 정보를 Meta 클래스에 지정
# articles/forms.py

from django import forms
from .models import Article

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = '__all__'

Meta Class

  • ModelForm의 정보를 작성하는 곳
  • ModelForm을 사용할 경우 참조할 모델이 있어야 하는데, Meta class의 model 속성이 이를 구성
  • 참조하는 모델에 정의된 field 정보를 Form에 적용
    • fields 속성에 ‘__all__’를 사용하면 모델의 모든 필드를 포함할 수 있음

      class ArticleForm(forms.ModelForm):
          class Meta:
              model = Article
              fields = '__all__'
    • exclude 속성을 사용하면 모델에서 포함하지 않을 필드를 지정할 수 있음

      class ArticleForm(forms.ModelForm):
          class Meta:
              model = Article
              exclude = ('title',)

ModelForm 구현하기

주요 method

is_valid()

  • 유효성 검사를 실행하고 데이터가 유효한지 여부를 boolean으로 반환
  • 데이터 유효성 검사를 보장하기 위한 많은 테스트에 대해 Django는 is_valid()를 제공하여 개발자의 편의를 도움

save()

  • form 인스턴스에 바인딩된 데이터를 통해 데이터베이스 객체를 만들고 저장
  • ModelForm 하위 클래스는 키워드 인자 instance 여부를 통해 생성할지, 수정할지 결정
    • 제공되지 않은 경우 save()는 지정된 모델의 새 인스턴스를 만듦 (CREATE)
    • 제공되면 save()는 해당 인스턴스를 수정(UPDATE)
# CREATE

form = ArticleForm(request.POST)
article = form.save()

# UPDATE

form = ArticleForm(request.POST, instance=article)
form.save()

Create

  • 유효성 검사를 통과하면 데이터 저장 후 상세 페이지로 리다이렉트
  • 통과하지 못하면 작성 페이지로 리다이렉트
def create(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            article = form.save()
            return redirect('articles:detail', article.pk)
				return redirect('articles:create')
    else:
        form = ArticleForm()
		    context = {'form':form }
		    return render(request, 'articles/create.html', context)
  • 중복되는 로직 정리하면
def create(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            article = form.save()
            return redirect('articles:detail', article.pk)
    else:
        form = ArticleForm()

    context = {'form':form }
    return render(request, 'articles/create.html', context)

Update

  • ModelForm의 인자 instance는 수정 대상이 되는 객체(기존 객체)를 지정
  • request.POST : 사용자가 form을 통해 전송한 데이터(새로운 데이터)
  • instance : 수정이 되는 대상

update view 수정

def update(request, pk):
    article = Article.objects.get(pk=pk)
    if request.method == 'POST':
        form = ArticleForm(request.POST, instance=article)
        if form.is_valid():
            form.save()
            return redirect('articles:detail', pk=article.pk)
    else:
        form = ArticleForm(instance=article)
    context = {'form': form,
								'article':article }
    return render(request, 'articles/update.html', context)

update template 수정

{% extends 'base.html' %}

{% block content %}
  <h1>글수정</h1>
  <hr>

  <form action="{% url 'articles:update' article.pk %}" method="POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type="submit">
  </form>

  <hr>
  <a href="{% url 'articles:detail' article.pk %}">돌아가기</a>
{% endblock content %}

⭐️ Form vs ModelForm

  • ModelForm이 Form보다 더 좋은 것이 아니라 각자 역할이 다른 것
  • Form
    • 사용자의 입력을 필요로 하며 직접 입력 데이터가 DB 저장에 사용되지 않거나 일부 데이터만 사용될 때
    • 예 - 로그인, 사용자의 데이터를 받아 인증 과정에서만 사용 후 별도로 DB에 저장하지 않음
  • ModelForm
    • 사용자의 입력을 필요로 하며 입력을 받은 것을 그대로 DB 필드에 맞춰 저장할 때
    • 데이터의 유효성 검사가 끝나면 데이터를 각각 어떤 레코드에 맵핑해야 할지 이미 알고 있기 때문에 곧바로 save() 호출이 가능

🔥 전체 코드 확인

완성된 프로젝트 전체 코드 확인하기

profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

3개의 댓글

comment-user-thumbnail
2023년 4월 26일

꿈나무님, DRF 내용도 올리실 예정인가요 ? 올라온다면 언제쯤 올리실 예정이실까요 ?

1개의 답글