지난번엔 html파일에서 태그를 하나씩 직접 달아서 post로 보내는 방식으로 게시물을 생성했지만, 이번에는 장고에서 제공하는 Form과 ModelForm을 이용해서 좀 더 간단하고 효율적으로 처리할 수 있다.
역할 : Form 클래스의 데이터를 읽어서 HTML 입력폼을 알아서 만들어주고 유효성 검증 및 값 반환이 쉽다.
Form과 ModelForm의 차이 : Form은 직접 필드를 정의하고 위젯 설정이 필요하지만, ModelForm은 지정된 Model로 부터 필드 정보를 읽고 자동으로 필드를 설정한다.
실습
지난번에 한 실습에서 파일들을 좀 수정하면서 진행
blog / models.py 수정
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
contents = models.TextField()
main_image = models.ImageField(upload_to='blog/%Y/%m/%d/', blank=True, null=True) # mysite/blog/연/월/일 폴더에 저장한다
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
blog 파일 안에 form.py를 생성
Form 클래스를 사용할때는 직접 필드를 생성
from django import forms
class PostForm(forms.Form):
title = forms.CharField(max_length=20)
contents = forms.CharField()
main_image = forms.ImageField(required=False)
ModelForm을 사용할때는 내부에 Meta 클래스 사용
from django import forms
from .models import Post
class PostForm(forms.ModelForm): # ModelForm 상속
class Meta:
model = Post # models.py의 Post클래스를 model로 하겠다.
fields = ("title", "contents", "main_image") # Form에서 받아올 필드 작성. '__all__'를 사용하면 model의 모든 요소 선택
blog / views.py 수정
Form을 사용할 때
from django.shortcuts import render, get_object_or_404, redirect # 추가
from .models import Post
from django.db.models import Q # 쿼리 객체 Q import
from .forms import PostForm # forms.py 에서 PostForm클래스 import
def index(request):
if request.GET.get('q'): # GET요청에서 q가 있으면 : 검색 버튼을 눌렀을때
q = request.GET.get('q')
db = Post.objects.filter(Q(title__icontains=q) | Q(contents__icontains=q)).distinct() # Q 객체를 이용해서 &(and)와 |(or) 연산을 할 수 있다. distinct() : 중복 제거
else:
db = Post.objects.all()
context = {
'db': db,
}
return render(request, 'blog/index.html', context)
def post(request, pk):
db = Post.objects.get(pk=pk)
context = {
'db': db,
}
return render(request, 'blog/post.html', context)
def create(request): # 게시물 생성
if request.method == "POST": # request가 POST면 : 게시 버튼을 누르면
form = PostForm(request.POST, request.FILES) # PostForm에 Post요청값과 파일들을 넣어서 form 생성.
if form.is_valid(): # form 유효성 검사 : DB와 형식이 일치하면
post = Post( # Post객체 post 생성
title = form.cleaned_data['title'], # 아까 만든 form의 cleaned_data를 이용해서 dict형태로 접근
contents = form.cleaned_data['contents'],
main_image = form.cleaned_data['main_image'],
)
post.save() # DB에 저장
return redirect('blog:post', pk=post.pk) # 생성 후 게시물의 상세보기로 이동.
else:
form = PostForm() # POST 요청이 아니면 PostForm형식에 맞게 form 생성
return render(request, 'blog/create.html', {'form': form})
def update(request, pk): # 게시물 수정 (업데이트)
post = get_object_or_404(Post, pk=pk) # get_object_or_404 : Post.obejcts.get(pk=pk)가 있으면 post로 지정, 없으면 404를 반환하는 함수
if request.method == "POST": # request가 POST면 : 수정하기를 누르면
form = PostForm(request.POST, request.FILES) # request로 form 생성
if form.is_valid(): # form 유효성 검사 : DB와 형식이 일치하는지
post.title = form.cleaned_data['title'] # 요소 하나씩 수정
post.contents = form.cleaned_data['contents']
if form.cleaned_data['main_image']: # 이미지가 있으면 업데이트
post.main_image = form.cleaned_data['main_image']
post.save() # DB에 저장
return redirect('blog:post', pk=post.pk) # 수정 후 게시물의 상세보기로 이동
else:
initial_data = { # 수정하기 전 게시물 데이터 값 받아오기
'title': post.title,
'contents': post.contents,
'main_image': post.main_image,
}
form = PostForm(initial=initial_data) # 수정 하기 전 게시물 데이터를 넣은 PostForm으로 생성
return render(request, 'blog/create.html', {'form': form})
def delete(request, pk): # 게시물 삭제
post = get_object_or_404(Post, pk=pk) # get_object_or_404 : Post.obejcts.get(pk=pk)가 있으면 post로 지정, 없으면 404를 반환하는 함수
if request.method == "POST": # POST요청이면 : 삭제 버튼을 눌렀으면
post.delete() # 지정한 post를 DB에서 삭제
return redirect('blog:index') # 삭제한 후 메인으로 이동
return render(request, 'blog/delete.html', {'post': post}) # post 요청이 아닐때는 delete.html render해주기
ModelForm을 사용할 때의 create과 update
def create(request): # 게시물 생성
if request.method == "POST": # request가 POST면 : 게시 버튼을 누르면
form = PostForm(request.POST, request.FILES) # PostForm에 Post요청값과 파일들을 넣어서 form 생성.
if form.is_valid(): # form 유효성 검사 : DB와 형식이 일치하면
post = form.save() # ModelForm일때는 이렇게 DB에 저장가능
return redirect('blog:post', pk=post.pk) # 생성 후 게시물의 상세보기로 이동.
else:
form = PostForm() # POST 요청이 아니면 PostForm형식에 맞게 form 생성
return render(request, 'blog/create.html', {'form': form})
def update(request, pk): # 게시물 수정 (업데이트)
post = get_object_or_404(Post, pk=pk) # get_object_or_404 : Post.obejcts.get(pk=pk)가 있으면 post고 없으면 404를 반환하는 함수
if request.method == "POST": # request가 POST면 : 수정하기를 누르면
form = PostForm(request.POST, request.FILES, instance=post) # instance=post : ModelForm은 instance 매개변수를 통해 수정할 모델 객체 지정
if form.is_valid(): # form 유효성 검사 : DB와 형식이 일치하는지
form.save() # DB에 저장
return redirect('blog:post', pk=post.pk) # 수정 후 게시물의 상세보기로 이동
else:
form = PostForm(instance=post) # ModelForm은 instance매개변수를 이용해서 form의 값을 미리 받아온다.
return render(request, 'blog/create.html', {'form': form})
templates / blog 안에 html 파일 수정
menu.html
<h2><a href="{% url 'blog:index' %}">My Blog</a></h2>
{% block content %}
{% endblock %}
index.html
{% extends 'blog/menu.html' %}
{% block content %}
<h1>게시판</h1>
<form action="" method="get">
<input name="q" type="search">
<button type="submit">검색</button>
</form>
<ul>
{% for post_detail in db %}
<li>
<a href="{% url 'blog:post' post_detail.id %}">{{ post_detail.title }}</a>
<p>{{post_detail.contents}}</p>
</li>
{% endfor %}
</ul>
<button type="button" onclick="location.href='{% url 'blog:create' %}'">글쓰기</button>
{% endblock %}
post.html
{% extends 'blog/menu.html' %}
{% block content %}
<h1>게시판</h1>
<p>{{db.title}}</p>
<p>{{db.contents}}</p>
<p>{{db.updated_at}}</p>
{% if db.main_image %}
<img src="{{ db.main_image.url }}" alt="">
{% endif %}
<br>
<button type="button" onclick="location.href='{% url 'blog:update' db.pk %}'">수정하기</button>
<button type="button" onclick="location.href='{% url 'blog:delete' db.pk %}'">삭제하기</button>
{% endblock %}
create.html
{% extends 'blog/menu.html' %}
{% block content %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
{% endblock %}
delete.html
{% extends 'blog/menu.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
<p>블로그 글 "{{post.title}}" 을 삭제하시겠습니까?</p>
<input type="submit" value="네!" class="btn btn-primary">
</form>
{% endblock %}
결과
'Django' 카테고리의 다른 글
Django 실습(7) 클래스 기반 뷰 (Class-Based Views) 이용하기 (1) | 2023.10.16 |
---|---|
Django 실습(6) Login 기능 구현하기 (0) | 2023.10.13 |
Django ORM을 이용해서 DB CRUD 해보기 (0) | 2023.10.11 |
Django 실습(4) Model과 DB를 이용한 게시물 관리와 업로드 (1) | 2023.10.11 |
Django 실습(3) Bootstrap 사용해서 블로그 만들고 꾸미기 (0) | 2023.10.10 |