임포트 할 모듈
from django.http import HttpResponse, HttpResponseNotAllowed
from django.shortcuts import redirect, render, get_object_or_404
from django.contrib.auth.decorators import login_required
from post.models import Post, Comments, PostLike, CommentLike
from django.conf import settings # media url
from .forms import PostForm, ImageForm, FileForm, CommentForm
from django.contrib import messages
from django.urls import reverse
인덱스함수 :
def index(request):
posts = Post.objects.all().order_by("-created_at")
#꺼꾸로 최신글 부터 위로 오게 설정
if request.method == "GET":
return render(
request,
"post/index.html",
{"posts": posts, "MEDIA_URL": settings.MEDIA_URL},
)
elif request.method == "POST":
pass
else:
return HttpResponse("Invalid request method", status=405)
게시물 생성 함수 :
만약 한개의 이미지만 가져오고 싶었을때와 폼 없이 저장하고 싶었을때:
@login_required(login_url="/users/login/")
# 즉, 로그인 되어있지 않을시 로그인 페이지로 옮겨
#if request.user.is_authenticated:해준 모든것을 알아서 처리해준다.
def create(request):
#if request.user.is_authenticated:
if request.method == "POST":
title = request.POST['title']
author =request.user
content =request.POST['content']
#한개의 이미지
image =request.FILES.get('image')
file = request.FILES.get('file')
Post.objects.create(
title = title,
author =author,
content=content,
image = image,
file = file,
)
#여러개의 이미지 : 폼을 안쓰고
#1번쨰 방식
for img_file in request.FILES.getlist('images'):
Image.objects.create(post=post, image=img_file)
for file in request.FILES.getlist('files'):
File.objects.create(post=post, file=file)
#2번쨰 방식
# for f in file:
# file_instance = File(file=f) # 클라스 인스턴스 생성
# file_instance.save()
# for img in image:
# img_instance = Image(image=img)
# img_instance.save()
return redirect('/post/')
elif request.method =="GET":
return render(request,'post/create.html')
else:
return HttpResponse("Invalid request method" , status=405)
# else: # if not request.user.is_authenticated:
# 로그인전 새로만들기 눌렀을때 로그인페이지로 next값 저장해주고 넘어가게해주기위해 만든것
# login_url = f"/user/login/?next={request.path}"
# return redirect(login_url)
form은 모델과 연동을 통해 여러 파일,사진등을 자동적으로 데이터의 생성, 수정, 유효성 검사, 에러 메시지 표시 등에 관련 기능이 풍부하기 떄문에 사용.
이번 프로젝트 에서는 더 templates와 연결할때 사용할 수 있는 편리한 FORM기능을 사용하지는 않음. 왜냐면 따로 <input ~~ multiple>같은 옵션을 걸어줘야할때는 사용할 수 없기 때문에.
허나 유효성검사 및 데이터 생성 수정 연결....해줌!
@login_required(login_url="/users/login/")
def create(request):
# if request.user.is_authenticated:
if request.method == "POST":
post_form = PostForm(request.POST, request.FILES) # 폼 인스턴스 생성
if post_form.is_valid(): # 유효성 검사
post = post_form.save(commit=False)
#commit=False해줄 시 바로 디비에 저장되지않고 폼만 형성되어 대기.
#해주는 이유는 templates에서 받지 못한 값을 따로 저장해 주기 위해서
post.author = request.user
post.save()
for img_file in request.FILES.getlist("image"):
#getlist를 통해서 request된 FILES의 모든 이미지를 받아 오는것
#for문으로 하나씩 돌려
image_form = ImageForm({"post": post.id}, {"image": img_file}) #정확히 어떤 위치의 포스트에 어떤 파일을 지정해주는것.
if image_form.is_valid():
image = image_form.save(commit=False)
image.post = post
image.save()
else:
#print(image_form.errors) #디버깅
#이렇게 에러메세지를 터미널에 볼수 있어 FORM에러메세지 기능
image_form = ImageForm()
# 처음 방문할 때 폼 객체가 존재하지 않기 때문에 생기는 오류를 방지
#템플릿에서 {{ form.as_p }} 등의 폼 렌더링 메서드를 사용할 경우 오류가 발생할 수 있기때문에 => 애초에 사용하지않았지만 해준다.
# context = {'post_form': post_form, 'image_form' : image_form , 'file_form':file_form}
return render(
request, "post/create.html", {"image_form": image_form}
)
for file in request.FILES.getlist("file"):
file_form = FileForm({"post": post.id}, {"file": file})
if file_form.is_valid():
file = file_form.save(commit=False)
file.post = post
file.save()
else:
#print(f"file{file_form.errors}")
file_form = FileForm()
return render(request, "post/create.html", {"file_form": file_form})
return redirect("/post/")
else:
print(post_form.errors)
post_form = PostForm()
return render(request, "post/create.html", {"post_form": post_form})
elif request.method == "GET":
posts = Post.objects.all()
return render(request, "post/create.html", {"posts": posts})
else:
return HttpResponseNotAllowed(["GET", "POST"])
#else:
#로그인전 새로만들기 눌렀을때 로그인페이지로 next값 저장해주고 넘어가게해주기위해 만든것
#login_url = f"/user/login/?next={request.path}"
#return redirect(login_url)
위에는 폼을 사용해주었고 참고로 폼셋도사용해봤지만 TEMPLATES와 연결해주는것에 에러가 자꾸 나서 폼으로 사용해 주었다.
폼셋을 예를 들어주면:
ImageFormSet = modelformset_factory(
Image, form=ImageForm, extra=0) # extra : 추가적인 빈폼 갯수
form = ImageFormSet(request.POST, request.FILES, queryset=post.images.all())# post.images.all()는 특정 post와 연결된 모든 Image 객체를 반환합니다. 따라서 이 폼셋은 해당 post와 관련된 이미지만을 표시하고 편집 # queryset는 폼셋의 초기 상태를 정확하게 제어하기 위해 사용되며, 이를 통해 사용자가 특정 데이터만을 볼 수 있도록 하거나 특정 데이터에 대한 작업만을 수행하도록 제한. # 안해주면 데이터베이스에 있는 모든 이미지에 대한 폼이 표시
폼으로 여러개 파일이미지 업뎃 및 그 이전 파이 불러와 삭제 해주는 기능:
여기서 삭제기능은 폼을 설정할때 boolean타입으로 IMAGE 및 file의 위젯을 변경해주었다.
@login_required(login_url="/users/login/")
def update(request, post_id):
post = get_object_or_404(Post, pk=post_id)
current_images = post.images.all() #저장된 이미지를 모두 불러와.
current_files = post.files.all()
post_form = PostForm(request.POST, instance=post)
#instance=post는 이전의 저장된 포스트를 불러오는것.
#즉, instance 인자를 불러오지않으면 새로운 객체를 생성하느것이고, INSTANCE를 부를시 그 객체를 불러와 수정한다는 의미이다.
# 로그인한자와 글쓴이가 같은지
if request.user != post.author:
messages.error(request, "삭제권한이 없습니다")
return redirect("post:detail", post_id=post.id)
if request.method == "POST":
# 이미지 수정 및 삭제
if post_form.is_valid():
post = post_form.save(commit=False)
post.author = request.user
post.save()
# print(post_form.instance.id) 디버깅 체크
else:
post_form = PostForm(instance=post)
#
return redirect("post:home")
# 기존의 저장된 파일 들을 삭제할것인지
for img in current_images:
image_form = ImageForm(
request.POST, request.FILES or None, instance=img, prefix=str(img.id)
#request.FILES or None을 해주는 이유는 만약 아무런 데이터가 없어 즉, 이미지를업로드 시키지 아니아하였을때 .is_valid()유효성 체크시 None => false가 나올수 있기때문에 넣어준다.
)
if image_form.is_valid():
if f"delete_{img.id}" in request.POST:
# template에서 전해주는 name을 확인해서 넘겨준다.
#<label>삭제하기: <input type="checkbox" name="delete_{{ form.instance.id }}" value="{{ form.instance.id }}" /></label>
#위의 체크박스를 넣어주고 그걸 연결시켜 값을 보내주는것.
img.delete()
else:
image_form = ImageForm(instance=img)
return HttpResponse("Invalid image", status=405)
for file in current_files:
file_form = FileForm(
request.POST, request.FILES or None, instance=file, prefix=str(file.id)
)
if file_form.is_valid():
if f"delete_{file.id}" in request.POST:
file.delete()
else:
file_form = FileForm(instance=file)
return HttpResponse("Invalid file", status=405)
#새롭게 추가하여 더해줄 파일들
for img_file in request.FILES.getlist("image"):
new_image_form = ImageForm({"post": post.id}, {"image": img_file})
if new_image_form.is_valid():
print("imageform ")
image = new_image_form.save(commit=False)
image.post = post
image.save()
else:
new_image_form = ImageForm()
return HttpResponse("Invalid image", status=405)
for f_file in request.FILES.getlist("file"):
new_file_form = FileForm({"post": post.id}, {"file": f_file})
print("fileform ")
if new_file_form.is_valid():
file = new_file_form.save(commit=False)
file.post = post
file.save()
else:
new_file_form = FileForm()
return HttpResponse("Invalid file", status=405)
return redirect("post:detail", post_id=post.id)
# 위에 다 수정을 해줫으면 새로히 수정된 내용 저장[] 해주고
# 이름에 의해 일어날 충돌을 막기 위해서 앞에 이름을 덧 붙혀준것 => prefix=str(~.id)
# 다 이미지 폼으로 생성되면서 충돌이 생길까봐.
image_forms = [
ImageForm(prefix=str(img.id), instance=img) for img in current_images
]
file_form = [FileForm(prefix=str(file.id), instance=file) for file in current_files]
return render(
request,
"post/update.html",
{
"post": post,
# 'post_from' : post_form,
"image_forms": image_forms,
"file_form": file_form,
},
)
게시물을 삭제하는 메소드:
@login_required(login_url="users:login")
def delete(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.user != post.author:
messages.error(request, "삭제권한이 없습니다")
return redirect("post:detail", post_id=post.id)
else:
post.delete()
return redirect("post:home")