티스토리 뷰
modelform은 다음과 같이 이루어진다.
원래는 post_form.html의 1번이 있다면,
forms.py의 class(forms.Form)에서 models.py(models.Model)로 전달되었다가, DB로 전달된다.
그런데 ModelForm을 선언하면, model을 기반으로 form을 자동으로 만들어준다.
class 클래스명(forms.ModelForm):
class Meta:
model = 모델명
fields = [필드명 1, 필드명2, ...] 또는 '__all__'로 만든다.
필드를 각각 안 만들거라 하면 all을 쓰는 것이다.
forms.py에 적는다.
from .models import Post
class PostModelForm(forms.ModelForm):
class Meta:
model=Post
fields = ['title','body']
그리고 views.py에서, form의 객체를 바꿔준다.
from .forms import PostForm, PostModelForm
def post_create..
form= PostModelForm(request.POST)
ModelForm.save()
DB에 새로운 레코드를 추가하려면, 3가지 방법이 있다.
1. 모델 인스턴스를 생성하고 save() 메소드 호출
2. 모델명.objects.create(필드값) 메소드 호출
3. ModelForm의 save() 메소드 호출
이 중 3번째에 대해서 진행한다.
def save(self,commit=True):
모델인스턴스명 = 모델명(**self.cleaned_data)
if commit:
모델인스턴스명.save()
return 모델인스턴스명
이제 view 부분에서
post = Post.objects.create(**form.cleaned_data)
를
post = form.save()
로 바꿔준다.
데이터 수정
view에 추가한다.
def post_update(request, id):
post = get_object_or_404(Post, id=id)
if request.method == 'POST':
form = PostModelForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect('blog:list')
else:
form = PostModelForm(instance=post)
return render(request, 'blog/post_update.html', {'form':form})
이 함수는 해당 PostModelForm에서 post를 instance로 가진다.
그래서 해당 페이지가 고쳐지면, 해당 변화를 save 해준다.
path('update/<id>/', views.post_update, name='update'),
당연히 이제 수정 페이지도 만들어줘야 한다.
post_update.html의 페이지를 만든다.
{% extends "layout.html" %}
{% block title %}Post 수정{% endblock %}
{% block content %}
<h1> POST 수정</h1>
<form action="" method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="수정">
</form>
{% endblock %}
그리고 당연히 글 수정에 대한 태그를 게시판 페이지인 detail에 추가해준다.
<a href ="{% url 'blog:update' post.id %}"> [글수정]</a>
데이터 삭제
당연히 데이터 삭제도 post_delete.html을 이용해서 추가해준다.
post_delete.html
{% extends "layout.html" %}
{% block title %}
Post 삭제
{% endblock %}
{% block content %}
<h1>POST 삭제</h1>
{{post}} 글을 정말로 삭제하시겠습니까?
<form action="" method="POST">
{% csrf_token %}
<input type="submit" value="네, 삭제합니다" />
</form>
<a href="{% url 'blog:list'%}">아니오, 취소합니다</a>
{% endblock %}
def post_delete(request, id):
post = Post.objects.get(id=id)
if request.method == 'POST':
post.delete()
return redirect('blog:list')
else:
return render(request, 'blog/post_delete.html', {'post': post})
만약에 delete가 불러와지면 delete를 실행한다.
아니라면 해당 페이지를 표시한다.
역시에 해당 페이지에 대한 path도 추가해준다.
path('delete/< id>/', views.post_delete , name='delete'),
그리고 글 삭제만 추가하면?
<a href ="{% url 'blog:delete' post.id %}"> [글 삭제]</a>
# delete 페이지에서, 넘어온 id까지 받는다.
간단하게 글 수정 및 삭제를 할 수 있다.
spring에서는 이게 매우 어렵다.
commit 지연
view 함수에서 commit true를 준다.
def save(self, commit=True):
모델 인스턴스명 = 모델명(**self.cleaned_data)
if commit:
모델인스턴스명.save()
return 모델인스턴스명
blog/models.py
class Post(model.Model):
ip = models.GenericIPAddressField(null=True)
커맨드 창에서 migrate를 해준다.
python manage.py makemigrations blog
python manage.py migrate blog
views.py에서, post_create에 commit을 고쳐준다.
def post_create(request):
if request.method == 'POST':
form = PostModelForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
post = form.save(commit=False) # commit=False로 저장 지연
post.ip = request.META['REMOTE_ADDR'] # 추가적인 처리
post.save() # 명시적으로 저장
return redirect(post)
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})
META 함수로 추가적인 처리를 한다.
이 경우에는 헤더에 포함된 ip를 불러온다.
그리고 runserver를 하면, post를 만들었을 때 ip가 들어간 것을 확인할 수 있다.
유효성 검사
사용자로부터 입력 받은 값은 처리하기 전에 올바른 값인지 판단해야 한다.
is_valid() 메소드로 판단하는데, 다음과 같은 특징을 가직 있다.
1. 입력값에 대한 모든 validator를 호출한다.
2. 유효한 입력값들은 cleaned_data 딕셔너리 요소로 저장한다.
3. 모든 입력값이 유효하면 True를 반환한다.
4. 유효하지 않은 입력값이 있다면 False를 반환하고 오류 메시지와 함께 입력폼으로 이동한다.
필드에 내장된 validator -> vlaidators 속성에 지정된 validator -> clean_필드명() 메소드 -> clean() 메소드
사용자 정의 validator를 사용할 수도 있다.
def 함수명(value):
#유효성 검사
#유효성 검사에 실패시 raise Validation Error('오류 메시지')
#유효성 검사 성공시 반환값 없음
validator 지정
class 모델명(models.Model):
필드명 = ~Field(validators=[validator1, validator2...])
class 폼명(forms.Form):
필드명 = ~Field(validators=[validator1, validator2...])
clean_필드명()
class PostForm(forms.Form):
title = forms.CharField(label='제목')
body = forms.CharField(label='내용', widget=forms.Textarea)
def clean_title(self):
# title 값 유효성 검사
def clean_body(self):
# body 값 유효성 검사
def clean(self):
title = self.cleaned_data.get('title')
body = self.cleaned_data.get('title')
#title과 body 값이 활용된 유효성검사
# 유효성 검사 실패시 raise ValidationError('오류메시지')
# 유효성 검사 성공시 return title
clean이라는 메소드를 만들어 놓으면, is_valid가 호출 될 때 자동으로 호출된다.
member/forms.py를 만든다.
member라는 어플리케이션을 만들고, 해당 form을 만드는 것이다.
python manage.py startapp member
멤버의 이름이 적절한지 검사하는 폼이다.
import re
from django import forms
from django.core.validators import MinLengthValidator
from django.forms import ValidationError
def username_validator(value):
if re.search('[^A-Za-z0-9.@+-]', value):
raise ValidationError('8자이상 150자 이하 문자, 숫자 그리고 @/./+/-/_만 가능합니다.')
class UserCreationForm(forms.Form):
username = forms.CharField(label='사용자 이름', max_length=150,
validators=[username_validator, MinLengthValidator(8)])
password1 = forms.CharField(label='비밀번호', widget=forms.PasswordInput(),
validators=[MinLengthValidator(8)])
password2 = forms.CharField(label='비밀번호 확인', widget=forms.PasswordInput())
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise ValidationError('비밀번호가 일치하지 않습니다.')
return password2
def clean(self):
username = self.cleaned_data.get('username')
password1 = self.cleaned_data.get('password1')
if username and password1 and password1.startswith(username):
raise ValidationError('사용자 이름과 비밀번호가 유사합니다.')
return self.cleaned_data