Skill/Django

[Django] CRUD를 더 탄탄하게(1)_forms & ModelForms

엉아_ 2021. 9. 11. 22:46
728x90

- form

: Django 프로젝트의 주요 유효성 검사 도구들 중 하나이며, 공격 및 우연한 데이터 손상에 대한 중요한 방어수단

 

 

1) Form 선언하기

# articles/forms.py

from django import forms

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

: forms 라이브러리에 있는 Form  클래스를 상속받음.

 

2) views에서 form을 사용하는 모습

# articles/views.py

from .forms import ArticleForm

def new(request):
    form = ArticleForm()
    context = {
    	'form': form
    }
    return render(...)

 

3) templates에서 form을 사용하는 모습

# articles/create.html

{% extends 'base.html' %}

{% block content %}
  <h1>CREATE</h1>
  <form action="{% url 'articles:create' %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit">
  </form>
  <hr>
  <a href="{% url 'articles:index' %}">[back]</a>
{% endblock  %}

 

4) Form rendering options

: as_p(), as_ul(), as_table()

 

- ModelForms

: Article 모델이 있고 사용자가 게시글을 제출할 수 있는 양식을 만들고 싶은 경우 이미 모델에서 필드를 정의했기 때문에 form 에서 필드를 재정의하는 중복된 행위가 발생한다.

: ModelFroms를 상속받아서 중복 행위를 줄이자!!

 

from django import forms
from .models import Article

class ArticleForm(forms.ModelForm):
	
    class Meta:
        model = Article
        fields = '__all__'  # 모든 필드를 넣고 싶을때
        # fields = ('title', 'content',)  # 특정 필드만 선택하고 싶을때
        # exclude = ('content',)  # 특정 필드를 빼고 싶을때

 

1) articles/views.py

: 기존의 new와 create 함수를 하나로 합치고, edit과 update를 하나로 합칠 수 있다!

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

- is_valid()

: 유효성 검사를 실행하고 True와 False를 반환

 

- save()

: ModelForm의 하위 클래스(ex ArticleForm)은 기존 모델 인스턴스를 instance로 받을 수 있는데 instance가 있으면 save는 해당 인스턴스를 업데이트하고 없으면 새 인스턴스를 만든다!

 

2) widgets

class ArticleForm(forms.ModelForm):
    title = forms.CharField(
        label='제목',
        widget=forms.TextInput(
            attrs={
                'class': 'my-title',
                'placeholder': '제목을 입력해주세요.',
                'maxlength': 10,
            }
        ),
        error_messages={
            'required':'제목을 입력해주세요!!!'
        }
    )
    content = forms.CharField(
        label='내용',
        widget=forms.Textarea(
            attrs={
                'class':'my-content',
                'placeholder': '내용을 입력해주세요.',
                'rows': 5,
                'cols': 50,
            }
        ),
        error_messages={
            'required':'내용을 입력해주세요!!!'
        }
    )

    class Meta:
        model = Article
        fields = '__all__'

- class : 부트스트랩의 class 사용 가능

- placeholder : input박스 안의 초기값을 작성할 수 있음

- maxlength : 길이 제한을 줄 수 있음

- rows, cols : 박스의 가로 세로 길이를 지정할 수 있음

 

- bootstrap

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block content %}
<form action="{% url 'articles:update' pk %}" method='POST' class='form' enctype="multipart/form-data">
  {% csrf_token %}
  <h1>UPDATE</h1>
  {% bootstrap_form form %}
  {% buttons submit="OK" reset="Cancel" %}{% endbuttons %}
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>
{% endblock content %}

: bootstrap 설치 후 load한뒤 form class에 bootstrap을 적용할 수 있다.

 

- Django shortcuts functions

  • render()
  • redirect()
  • get_object_or_404() : 해당 객체가 없을 경우 DoesNotExist 예외 대신 Http 404를 띄움
  • get_list_or_404()

 

- view decorators

: 요청 메서드에 따라 view 함수에 대한 엑세스를 제한함.

from django.views.decorators.http import require_http_methods, require_POST, require_safe

@require_safe
def index(request):
	...
    return render(request, 'articles/index.html', context)


@require_http_methods(['GET', 'POST'])
def create(request):
	...
    return render(request, 'articles/create.html', context)
  • require_http_methods() : 특정한 method 요청에 대해서만 허용하도록 하는 데코레이터
  • require_POST() : POST method 요청만 승인하도록 하는 데코레이터
  • require_safe() :  GET method 요청만 승인하도록 하는 데코레이터