# board/views.py
# 우선 제목과 내용만 받기
from django.shortcuts import render, redirect
from board.models import Post
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
def board(request):
# 게시글 리스트
if request.method == "GET":
page = request.GET.get('page', 1)
search_text = request.GET.get('search_text', "")
post_set = Post.objects.filter(
title__icontains=search_text
).order_by('-id')
paginator = Paginator(post_set, 2)
post_set = paginator.get_page(page)
context = {
"post_set":post_set,
"search_text":search_text,
}
return render(request, 'page/index.html', context=context)
@login_required(login_url="signin")
def post_write(request):
if request.method=="GET":
return render(request, "page/post_write.html")
if request.method=="POST":
title = request.POST["title"]
content = request.POST["content"]
Post(
title=title,
content=content,
).save()
return redirect('board')
<!-- post_write.html -->
{% extends 'common/base.html' %}
{% block content %}
<div class="card">
<div class="card-body text-end">
<form method="post" enctype="multipart/form-data" id="write_form">
{% csrf_token %}
<input class="form-control my-2" type="text" name="title" placeholder="제목" id="title">
<textarea
id="content"
style="height: 150px; resize: none;"
class="form-control my-2"
name="content"
placeholder="한번 작성한 글은 삭제할 수 없습니다. 매너를 지켜주세요!"
></textarea>
<input class="form-control" type="file" name="img" accept="image/*">
<a class="text-decoration-none fs-5 my-2" id="write_btn"
style="font-weight: bold;color: black;">글 작성</a>
</form>
</div>
</div>
<script>
let title = document.getElementById("title");
let content = document.getElementById("content");
let write_btn = document.getElementById("write_btn");
let write_form = document.getElementById("write_form");
write_btn.addEventListener("click", ()=>{
if(title.value === "" || content.value === ""){
alert("내용을 작성해 주세요.");
}else{
write_form.submit()
}
});
</script>
{% endblock %}
# board/views.py
from django.shortcuts import render, redirect
from board.models import Post
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
def board(request):
# 게시글 리스트
if request.method == "GET":
page = request.GET.get('page', 1)
search_text = request.GET.get('search_text', "")
post_set = Post.objects.filter(
title__icontains=search_text
).order_by('-id')
paginator = Paginator(post_set, 2)
post_set = paginator.get_page(page)
context = {
"post_set":post_set,
"search_text":search_text,
}
return render(request, 'page/index.html', context=context)
@login_required(login_url="signin")
def post_write(request):
if request.method=="GET":
return render(request, "page/post_write.html")
if request.method=="POST":
title = request.POST["title"]
content = request.POST["content"]
Post(
user=request.user,
title=title,
content=content,
).save()
return redirect('board')
#anonymous.settings.py
...
STATIC_URL = '/static/'
# 이부분 작성
MEDIA_ROOT = 'upload'
...
# board/views.py
from django.shortcuts import render, redirect
from board.models import Post
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from django.core.files.storage import default_storage
import uuid
def board(request):
# 게시글 리스트
if request.method == "GET":
page = request.GET.get('page', 1)
search_text = request.GET.get('search_text', "")
post_set = Post.objects.filter(
title__icontains=search_text
).order_by('-id')
paginator = Paginator(post_set, 2)
post_set = paginator.get_page(page)
context = {
"post_set":post_set,
"search_text":search_text,
}
return render(request, 'page/index.html', context=context)
@login_required(login_url="signin")
def post_write(request):
if request.method=="GET":
return render(request, "page/post_write.html")
if request.method=="POST":
title = request.POST["title"]
content = request.POST["content"]
img = request.FILES.get('img', None)
img_url = ""
if img:
img_name = uuid.uuid4()
ext = img.name.split('.')[-1]
default_storage.save(f"{img_name}.{ext}", img)
img_url = f"{img_name}.{ext}"
#이미지 저장!
Post(
img_url=img_url,
user=request.user,
title=title,
content=content,
).save()
return redirect('board')
오늘은 어제에 이어 게시판 글쓰기 form에 대한 백엔드 로직을 구현했다.
먼저, 제목과 내용에 해당하는 로직을 구성했는데, 사용자가 로그인되어 있지 않으면 글쓰기 페이지로 접근하더라도 로그인 페이지로 리다이렉팅될 수 있도록 했으며 로그인된 유저는 제목과 내용이 비어 있는 경우에만 글을 읽을 수 없도록 alert창을 띄워 막고 글을 업로드 할 수 있도록 했다.
그 다음, 이미지 파일 업로드에 해당하는 로직을 구현했다.
이미지의 경우 제목, 내용과는 다른 방식으로 작성되었기 때문에 ‘default storage’라는 다른 함수를 사용해야 했다.
이 함수를 사용하기 위해서는 django에서 약간의 설정을 해줘야 해서 설정부터 해줬다.
여기에서 주의할 점은, 다른 유저가 같은 제목을 글을 올릴 수 있다는 점이었기 때문에 유저를 구분하기 위해 img_name을 사용했다.
또한 확장자 역시 고려해야 하기 때문에 split으로 .을 기준으로 잘라내어 구현했다.
여기에서 한가지 고민했던 건 파일 확장자였다. 이미지도 png, jpg, jpeg 등 다양한데 모든 확장자를 잘 인식하고 저장할 수 있는지 여부가 가장 궁금했는데, 다행히 vscode와 github 모두에서 이미지가 잘 불러와졌다.
그리고 DBeaver에서도 post의 해당 글에 img_url이 잘 저장되어 있는 것까지 확인했다.
이렇게 글쓰기 로직에 대해서도 프론트엔드와 백엔드를 모두 완성했고, 앞으로의 강의 이름을 살펴보니 이제 게시판의 상세 페이지, 댓글까지의 기능이 남아있는 상태인 것 같다.
얼른 기능 개발을 마치고, 강의처럼 AWS를 이용하거나 비용 문제로 사용이 어렵다면 다른 무료 서비스를 이용해서라도 배포를 진행해보고 싶다는 생각이 많이 들었다!