[Django] CRUD를 더 탄탄하게(1)_forms & ModelForms
- 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 요청만 승인하도록 하는 데코레이터