티스토리 뷰
ModelForm (Form Class를 상속)
- Django Form Base
- 지정된 Model로부터 필드정보를 읽어들여, form fields 를 세팅
변경 전
def min_length_3_validator(value): if len(value) < 3: raise forms.ValidationError('3글자 이상 입력해주세요.') class PostForm(forms.Form): title = forms.CharField() content = forms.CharField(widget=form.Textarea) # ModelForm.save 인터페이스를 흉내내어 구현 def save(self, commit=True): post = Post(**self.cleaned_data) if commit: post.save() return post |
변경 후
class PostForm(forms.ModelForm): class Meta: model = Post fields = '__all__' # 전체 필드 지정. 혹은 list로 읽어올 필드명 지정 |
- 내부적으로 model instance를 유지
- 유효성 검증에 통과한 값들로, 지정 model instance로의 저장 (save)을 지원 (Create or Update)
문제점 : validator를 설정하지 못함, validator를 모델에 정의하는게 좋다.
# dojo/models.py def min_length_3_validator(value): if len(value) < 3: raise forms.ValidationError('3글자 이상 입력해주세요.') class Post(models.Model): title = models.CharField(max_length=100, validators=[min_length_3_validator]) |
form vs modelform
from django import forms from .models import Post class PostForm(forms.Form): title = forms.CharField() content = forms.CharField(widget=forms.Textarea) # 생성되는 Form Field는 PostForm과 거의 동일 class PostModelForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'content'] |
ModelForm.save(commit=True) #src
• Form의 cleaned_data를 Model Instance 생성에 사용하고, 그 Instance를 리턴
• commit=True : model instance의 save() 를 호출
• form.save() != instance.save()
• commit=False
• instance.save() 함수 호출을 지연시키고자할 때 사용
ModelForm.save(commit=True)
from django import forms from .models import Post class PostForm(forms.Form): title = forms.CharField() content = forms.CharField(widget=forms.Textarea) def save(self, commit=True): post = Post(**self.cleaned_data) if commit: post.save() return post |
ModelForm을 통해 새 포스팅 저장하기
from django.db import models from django.urls import reverse class Post(models.Model): title = models.CharField() content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def get_absolute_url(self): return reverse('myapp:post_detail', args=[self.id]) # dojo/forms.py from django import forms from .models import Post class PostModelForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'content'] ModelForm을 통해 새 포스팅 저장하기 from django.shortcuts import get_object_or_404, render from .forms import PostModelForm from .models import Post def post_new(request): if request.method == 'POST': form = PostModelForm(request.POST, request.FILES) if form.is_valid(): post = form.save() return redirect(post) else: form = PostModelForm() return render(request, 'myapp/post_form.html', {'form': form,}) <!-- myapp/templates/myapp/post_form.html --> <table> <form action="" method="post"> {% csrf_token %} {{ form.as_table }} <input type="submit" /> </form> </table> |
ModelForm.save(commit=False) 예제
from django.db import models class Comment(models.Model): author = models.CharField(max_length=20) message = models.TextField() ip = models.CharField(max_length=15) # 필드 추가 # dojo/forms.py class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['author', 'message'] # ip필드는 유저로부터 입력받지 않고, 프로그램으로 채워넣을 것이기에 제외 # dojo/views.py def comment_new(request): if request.method == 'POST': form = CommentForm(request.POST, request.FILES) if form.is_valid(): comment = form.save(commit=False) comment.ip = request.META['REMOTE_ADDR'] # IP를 기록하고 comment.save() # save() return redirect('/') else: form = CommentForm() return render(request, 'myapp/comment_form.html', {'form': form}) |
템플릿은 다른 Form 템플릿과 동일
Form에서는 유저에게 입력받을 필드만 기재를 하여야함, 나머지는 views에서 처리
기존
def post_new(request): if request.method == 'POST': # POST 요청일 때 form = PostForm(request.POST, request.FILES) if form.is_valid(): # validator check post = form.save() post.ip = request.META['REMOTE_ADDR'] post.save() return redirect('/dojo/') |
> save가 이중으로 진행되기때문에, commit=False를 통해 저장하지않고, 별로 save함수를 호출하여 저장한다.
# post_new 함수 총 코드
# url 설정 blog/urls.py
# html 글목록 페이지에 글쓰기 기능 추가 blog/templates/blog/post_list.html
# 수정 가능하도록 blog앱까지 등록
[당부의 말] Form을 끝까지 작성
'''
request.POST 데이터가 form clean함수를 통해 변경될 수도 있다..
'''
class CommentForm(forms.Form):
def clean_message(self):
return self.cleaned_data.get('message', '').strip() # 좌우 공백제거
# ---
form = CommentForm(request.POST)
if form.is_valid():
# request.POST : 폼 인스턴스 초기 데이터
message = request.POST['message'] # request.POST를 통한 접근 : BAD !!!
comment = Comment(message=message)
comment.save()
return redirect(post)
[적극 추천]
form = CommentForm(request.POST)
if form.is_valid():
# form.cleaned_data : 폼 인스턴스 내에서 clean함수를 통해 변환되었을 수도 있을 데이터
message = form.cleaned_data['message'] # form.cleaned_data를 통한 접근 : GOOD !!!
comment = Comment(message=message)
comment.save()
return redirect(post)
ModelForm을 활용한 Model Instance 수정 뷰
'''
ModelForm을 활용한 post_new뷰와 비교하여,
ModelForm 인스턴스 생성 시에 instance 인자로서 Model Instance를 지정해주는 차이 뿐.
'''
# myapp/views.py def post_edit(request, id): post = get_object_or_404(Post, id=id) # 모델 인스턴스 획득 if request.method == 'POST': form = PostModelForm(request.POST, request.FILES, instance=post) if form.is_valid(): post = form.save() return redirect(post) else: form = PostModelForm(instance=post) return render(request, 'myapp/post_form.html', {'form': form,}) |
"""본 내용은 AskDjango VOD, "장고 차근차근 시작하기" 강의내용을 참고하여 작성했습니다.(https://nomade.kr/)"""
'Python > * Django' 카테고리의 다른 글
21. Messages Framework (0) | 2017.12.28 |
---|---|
20. Form Template Custom Render (0) | 2017.12.27 |
18. Form (0) | 2017.12.19 |
17. HttpRequest and HttpResponse (0) | 2017.12.18 |
16. CSRF(Cross-Site Request Forgery) (0) | 2017.12.15 |