ModelForm // django Form(3)
2022. 4. 17. 17:03
- 인프런의 이진석 강사님의 장고강의를 참고
ModelForm
- 장고 Form을 상속받음
- 지정된 Model로부터 필드정보를 읽어들여, Form Fields를 세팅할 수 있다.
- 내부적으로 Model instance 생성하여 저장(create)하거나 업데이트(update)함
- 유효성 검증에 통과한 값들로, 지정된(연결되어 있는) Model instance로의 저장(save)이 가능. 저장된 객체가 이미 존재한다면(pk가 이미 있다면) update되고, 그렇지 않으면 create됨
일반 Form과 Model Form의 차이
- 일반 Form은 만들 field를 일일이 설정하고(title,content..), 그 field들의 속성도 설정해줘야 함(Charfield같은 것)
- 모델 Form은 어떤 모델과 연결할지, 그리고 연결된 모델의 어떤 필드를 사용할지만 정해주면 됨(핵편함)
- 실제로 모델과 연결될 경우 장고에서도 일반 Form보다는 Model Form을 사용할 것을 권함
- Serializer에도 ModelSerializer가 있으며, 역시 Model과 연결될 경우 Modelserializer를 쓰는 것이 편함
#forms.py
from django import forms
from .models import Post
#일반 form
class PostForm(forms.Form):
title =forms.CharField()
content =forms.CharField(widget=forms.Textarea)
#모델 form
class PostModelForm(forms.ModelForm):
class Meta:
model =Post
fields =['title','content']
ModelForm.save()
- 다음과 같은 view의 로직이 있다고 하자. 여기서 PostForm은 models.py에서 설정된 modelform이다.
- form.is_valid()가 실행되면 form의 모든 필드들에 대해 유효성 검사가 실행된다. 모든 필드들에 대한 유효성 검사가 성공적으로 끝나면 form.is_valid()는 True를 반환하며 유효성 검사가 실행된 값들은 form.cleaned_data에 담긴다
- 이때 modelform.save()를 실행시, form.cleaned_data에 담긴 값들을 기반으로 연결된 model의 instance를 생성하고 반환한다.
- 아래의 예시에서 form.save()라고 되어있지만, 이 form이 modelform인 postform의 인스턴스임.
- form.save()의 결과로 리턴된 model의 객체를 post가 받음. 즉 post는 새로이 생성된 model의 인스턴스
- post.save()를 통해 DB에 해당 객체가 저장됨
- modelform.save()는 commit이라는 값을 받음
- default = True로, True일 경우 자동적으로 model인스턴스.save()를 호출한다(즉 자동으로 db에 저장시킨다)
- 아래의 예시에서는 form.save(commit=True)였을 경우 자동적으로 post.save()가 호출되어서 DB에 저장되었을 것임. 즉 'modelform.save()'는 instance.save()와 다른 것이다.
- 그러면 commit=False를 왜 줄까? 코드만 길어지는데?
- form에서 다 채우지 못한 정보를 채우기 위해 instance.save()호출을(즉 db저장을) 지연시키려는 것임
- 예를 들어, post모델에서 반드시 입력해야 하는 작성자 정보는 form에서 입력할 수 있으면 안됨(작성자를 조작할 수 있으므로)
- 그러면 form에서 author 필드를 제외시키는데, 모델 instance가 db에 저장되기 위해서는 반드시 author가 어디선가 입력되어야 함
- 따라서 form에서 입력하지 못한 값들을 채우기 위해 일단 객체만 지정을 해서 받아두고, 받은 객체에 입력하지 못한 field의 값을 채워준 후에 instance.save()로 db에 저장하는 것임
- 의문)근데 field가 다 없으면 어케 유효성 검사(is_valid)가 통과하는 것임? A : form에 설정된 필드에 한해서만 유효성 검사를 진행함
- 참고)modelform에서 단순히 받은 정보를 새로이 생성하여 저장하기만 원한다면, form = postForm(request.POST) 등으로 form에 데이터를 넣어주고 form.save()만 해도 데이터는 저장이 됨
#forms.py
def post_new(request):
if request.method =="POST":
form = PostForm(request.POST,request.FILES)
if form.is_valid(): #form에 설정된 필드에 한해서만 유효성검사를 진행
#form필드에 다른 정보의 입력이 필요없다면 이렇게만 해도 db에 내용이 저장된다
#form.save()
post = form.save(commit=False)
post.author = request.user #request User = 현재 로그인 유저 인스턴스
post.save()
return redirect(post)
#get_absolute_url을 찾아감
else:
form = PostForm()
ModelForm을 활용한 수정
- get요청이 들어와서 빈 form을 줄때나 post로 온 요청데이터를 form에 다시 담을 때 모두 form instance를 만드는 과정이 필요하다
- 만약 Form이 ModelForm이라면, form instance를 만들 때 만들어진 form이 model의 어떤 instance와 연결되는지를 선언해주면, 해당 form instance를 통해 수행한 작업들이 연결된 model instance에 반영된다.
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)
#지금 값을 넣은 form객체가 모델form의 어느 instance와 연결이 되어있는지를 가르쳐주는 거임
if form.is_valid():
post = form.save()
return redirect(post)
#get_absolute_url을 찾아감
else:
form = PostForm(instance=post)
#instance=post를 줬기 때문에 form에 get요청을 하면 instance의 값들이 들어가있는 채로 바로 나옴
return render(request,'instagram/post_form.html',{
'form':form,
})
주의사항
- Form을 끝까지 사용해야 한다
- form에는 유효성검사(is_valid)가 끝이나면 자동으로 'clean_필드명' 함수를 호출하는 경우가 있음
- clean_필드명 함수는 커스터마이징된 유효성 검사와 더불어, 값을 조정하는 경우가 있음(문자열만 남긴다 등)
- clean_필드명 함수의 결과값이 자동으로 cleaned_data에 반영이 되므로, cleaned_data에서 값을 꺼내오는 방식이 로직 전체를 적용받을 수 있어서 훨씬 안전하다!
- request.POST에서 값을 꺼내오면, clean_필드명 함수로직을 타지 못할 수도 있음!!
#비추천방식
...
if form.is_valid()
message= request.POST['message']
#추천방식
...
if form.is_valid()
message= form.cleaned_data['message']
'django > basic' 카테고리의 다른 글
Form validation : django form(5) (0) | 2022.04.17 |
---|---|
CSRF 공격&CSRF Token // django form(4) (0) | 2022.04.17 |
HttpRequest와 HttpResponse // django form(2) (0) | 2022.04.17 |
HTML Form과 Django Form // django form(1) (0) | 2022.04.17 |
django view(8) : 뷰 장식자(decorator) (0) | 2022.04.16 |