[Djnago] ModelForm 알아보기
ModelForm
model 과 form 은 연관이 되어있습니다. 대체적으로 model의 field 에 해당하는 form filed 를 만들기 때문에 models.py
와 forms.py
를 작성하면 이는 대체로 비슷한 양상을 보입니다. 하지만 따로 작성하게 되면 각자를 따로 관리해줘야 하기 때문에 번거롭습니다. 다행히도 둘을 연결 시킨 ModelForm 이 존재하고 이는 form 을 상속받아 form 처럼 동작할 수 있으면서 model 과 쉽게 연결지을 수 있습니다. 지정한 model로 부터 필드를 읽어들어서 Form Fields 를 세팅 함으로서 field 를 하나하나 설정해줄 필요가 없습니다. 간단한 예시가 아래 나와있습니다.
# forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
ModelForm 을 통한 create 와 edit
기존에는 핵심이 되는 views 코드만 있었지만 전체적인 코드를 공개해달라는 요청이 많아서 전체적인 코드를 올리겠습니다.
기본적인 Post
모델과 이와 연결되는 ModelForm
을 만들었습니다.
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=10)
content = models.TextField()
# forms.py
from django import forms
from . models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
전체적인 post 들을 보여주는 home.html
과 글을 수정하거나 생성하는 post_form.html
입니다.
<!-- core/home.html -->
<h1>메인 화면</h1>
<a href="{% url 'post_create' %}">글쓰기</a>
<hr>
{% for post in post_list %}
<h3>{{ post.title }}</h3>
<div>{{ post.content }}</div>
<a href="{% url 'post_edit' post.pk %}">수정</a>
<hr>
{% endfor %}
<!-- core/post_form.html -->
<form action="" method="POST">
{% csrf_token %}
<table>
{{form.as_table}}
</table>
<input type="submit" value="제출">
</form>
home, 글 생성, 글 수정에 대한 url 입니다.
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.home, name="home"),
path('post_create/', views.post_create, name="post_create"),
path('post_edit/<int:pk>', views.post_edit, name="post_edit"),
]
글을 생성하고 수정하는 내용입니다.
수정시에는 instance=post
를 지정해줌으로서 기존에 있던 데이터를 불러올 수 있습니다.
# views.py
from django.shortcuts import render,redirect, get_object_or_404
from .forms import PostForm
from .models import Post
def home(request):
post_list = Post.objects.all()
context = {
'post_list': post_list,
}
return render(request, "core/home.html", context)
def post_create(request):
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save()
return redirect('home')
else:
form = PostForm()
context = {
'form' : form
}
return render(request, 'core/post_form.html', context)
def post_edit(request, pk):
post = get_object_or_404(Post,pk=pk)
if request.method == "POST":
form = PostForm(request.POST, request.FILES, instance=post)
if form.is_valid():
post = form.save()
return redirect(home)
else:
form = PostForm(instance=post)
context = {
'form': form,
}
return render(request, 'core/post_form.html', context)
저장을 잠시 미루기 위한 commit=False
현재까지의 코드는 사용자에게 form을 통해 입력받은 내용을 저장해서 새로운 인스턴스를 만듭니다. 지금의 문제는 사용자에게 입력 받는 것이 아닌 views 에서 로직을 통해 새로운 값을 넣을 수 없습니다. 이를 해결해보도록 하겠습니다.
기존의 Post
model 에 대해서 ip 라는 필드를 추가하였습니다. 해당 필드는 사용자로 부터 값을 받는 것이 아니라 views
에서 로직을 통해 추가합니다.
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=10)
content = models.TextField()
ip = models.CharField(max_length=20)
def __str__(self):
return self.title
이에 따라 forms 도 변경했습니다. all 로 지정시에는 ip도 받는 form 이 생기기 때문에 앞선 두 개의 필드만 지정해주었습니다.
# forms.py
from django import forms
from . models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
이제 값을 저장하지 않은 체로 post 를 받아와서 ip 필드를 채워준 후 다시 저장해주도록 합니다. commit=False
를 통해 post 에 해당하는 instance 들은 저장을 잠시 미룰 수 있습니다.
# views.py
def post_create(request):
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.ip = request.META['REMOTE_ADDR']
post.save()
return redirect('home')
else:
form = PostForm()
context = {
'form' : form
}
return render(request, 'core/post_form.html', context)
유효성을 통과한 값, cleand_data
form에는 이미 request
로 부터 넘어온 값이 유효성 검사를 마치고 저장이 되어있습니다. 따라서 form을 만들었다면 request.POST
로 기존의 값에 접근하기 보다는 cleand_data 를 통해서 접근하시는게더 좋습니다.
if request.method == "POST":
form = PostForm(request.POST, request.FILES)
if form.is_valid():
title = form.cleand_data['title'] # (O)
title = request.POST['title'] # (X)
return redirect('home')