Q&A
책을 따라하다가 막히는 부분이 있나요?
질문을 남겨주세요.
하지만, 책을 끝까지 읽고 나면 이 페이지도 만드실 수 있을거에요.
Post 작성 시 태그를 달면서 다음과 같은 에러가 발생했습니다.
1 year, 11 months ago
Gon관리자 페이지(admin) 페이지에서 작성한 태그는 글 작성이 되는데 관리자 페이지에 작성되어 있는 태그를 사용하지 않고 태그를 달아 블로그 게시물을 올리면 다음과 같은 에러가 나옵니다. 에러 구문은 다음 라인에서 발생했다고 합니다. 어디서 발생한 오류이며 해결 방안이 어떻게 되는지 물어보고 싶습니다.
views.py에서 발생했습니다.
views.py의 소스코드입니다.
# CBV 방식으로 변경하기
# from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView # Detail을 불러오겠음
# django -> views -> generic 안의 CreateView를 불러오겠음.
# 로그인 관련해서 django에서 지원해주는 라이브러리
# 로그인되어있을때만 보여줌
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
# UserPassesTestMixin : 스태프
from .models import Post, Category, Tag, Comment
from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import PermissionDenied
from django.utils.text import slugify
from .forms import CommentForm
from django.db.models import Q
# --------------------------------------------------------------------------------------------------------------
class CommentUpdate(LoginRequiredMixin, UpdateView):
model = Comment
form_class = CommentForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
return super(CommentUpdate, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
class PostUpdate(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category', 'tags']
# _form.html
template_name = 'blog/post_update_form.html'
# 원하는데로 보낼 수 있게 하는 방법
def get_context_data(self, **kwargs):
context = super(PostUpdate, self).get_context_data()
if self.object.tags.exists():
tags_str_list = list()
for t in self.object.tags.all():
tags_str_list.append(t.name)
context['tags_str_default'] = ';'.join(tags_str_list)
return context
def form_valid(self, form):
response = super(PostUpdate, self).form_valid(form)
self.object.tags.clear()
tags_str = self.request.POST.get('tags_str') # POST : post 방식으로 매서드가 온 것
if tags_str:
tags_str = tags_str.strip() # strip() : 공백 제거
tags_str = tags_str.replace(',', ';') # ,를 ;로 변경하기
tags_list = tags_str.split(';') # ;을 기준으로 전부 나눠짐
for t in tags_list:
t = t.strip()
tag, is_tag_created = Tag.objects.get_or_create(name=t)
# 같은 이름을 갖는 태그가 없으면 생성하고, 있으면 그대로 가져온다.
if is_tag_created:
tag.slug = slugify(t, allow_unicode=True)
# 새로 생성된 것이 있으면 한글 처리한다.
tag.save()
self.object.tags.add(tag)
return response
# dispatch
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
return super(PostUpdate, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
# 권한이 없다는 것을 알려줌
class PostCreate(LoginRequiredMixin, CreateView, UserPassesTestMixin):
model = Post # Post 모듈을 사용하겠음
fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']
def test_func(self):
return self.request.user.is_superuser or self.request.user.is_staff
def form_valid(self, form):
current_user = self.request.user
if current_user.is_authenticated and (current_user.is_staff or current_user.is_superuser):
form.instance.author = current_user
response = super(PostCreate, self).form_valid(form)
tags_str = self.request.POST.get('tags_str') # POST : post 방식으로 매서드가 온 것
if tags_str:
tags_str = tags_str.strip() # strip() : 공백 제거
tags_str = tags_str.replace(',',';') # ,를 ;로 변경하기
tags_list = tags_str.split(';') # ;을 기준으로 전부 나눠짐
for t in tags_list:
t = t.strip()
tag, is_tag_created = Tag.objects.get_or_create(name=t)
# 같은 이름을 갖는 태그가 없으면 생성하고, 있으면 그대로 가져온다.
if is_tag_created:
tag.slug = slugify(t, allow_unicode=True)
# 새로 생성된 것이 있으면 한글 처리한다.
tag.save()
self.object.tags.add(tag)
return response
else:
return redirect('/blog/')
class PostList(ListView):
model = Post
ordering = '-pk'
# Post 나열
# index 함수의 역할을 대신하게 된다.
# Blog의 urls를 전부 수정해야 한다.
# Older, Newer
paginate_by = 5
# None인 category가 몇 개가 있는가?
def get_context_data(self, **kwargs):
context = super(PostList, self).get_context_data()
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Post.objects.filter(category=None).count()
return context
class PostDetail(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDetail,self).get_context_data()
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Post.objects.filter(category=None).count()
context['comment_form'] = CommentForm
return context
# path('category/<str:slug>/',views.category_page),에서 옴
def category_page(request, slug):
if slug == 'no_category':
category = "미분류" # 카테고리가 없으면 미분류
post_list = Post.objects.filter(category=None)
else:
category = Category.objects.get(slug=slug)
post_list = Post.objects.filter(category=category)
return render(
request,
'blog/post_list.html',
{
'post_list':post_list,
'categories':Category.objects.all(), # 카드를 채워준다.
'no_category_post_count':Post.objects.filter(category=None).count(), # 미분류, 미분류 개수 알려줌
'category': category, # 제목 옆에 카테고리 이름이 붙는다.
}
)
# 태그 페이지
def tag_page(request, slug):
tag = Tag.objects.get(slug=slug)
post_list = tag.post_set.all()
return render(
request,
'blog/post_list.html',
{
'post_list':post_list,
'tag':tag,
'categories':Category.objects.all(),
'no_category_post_count':Post.objects.filter(category=None).count(),
}
)
def new_comment(request, pk):
if request.user.is_authenticated:
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid(): # 정상적으로 가져왔으면
comment = comment_form.save(commit=False) # 잠시 저장을 미룬다.
comment.post = post
comment.author = request.user
comment.save()
return redirect(comment.get_absolute_url())
else:
return redirect(post.get_absolute_url())
else:
raise PermissionDenied
def delete_comment(request, pk):
comment = get_object_or_404(Comment, pk=pk)
post = comment.post
# 로그인이 되어 있고 작성자가 자신이라면
if request.user.is_authenticated and request.user == comment.author:
comment.delete()
return redirect(post.get_absolute_url())
else:
raise PermissionDenied
class PostSearch(PostList):
paginate_by = None # 검색 결과를 전부 다 보여주도록 설정하기
def get_queryset(self):
q = self.kwargs['q']
post_list = Post.objects.filter(
Q(title__contains=q) | Q(tags__name__contains=q)
).distinct() # distinct : 중복 제거
return post_list # 타이틀과 태그에서 찾은 자료를 중복 없는 자료를 반환
def get_context_data(self, **kwargs):
context = super(PostSearch, self).get_context_data()
q = self.kwargs['q']
context['search_info'] = f'Search : {q} ({self.get_queryset().count()})'
return context
추가로 urls.py와 admin.py도 올리겠습니다. 문제점 봐주시면 감사하겠습니다.
urls.py
from django.urls import path
from . import views
# . : 현재 디렉토리(blog->urls)
# 경로 urls.py -> index.py
urlpatterns = [
path('search/<str:q>/',views.PostSearch.as_view()), # 글 검색하기
path('delete_comment/<int:pk>/', views.delete_comment),
path('update_comment/<int:pk>/', views.CommentUpdate.as_view()),
path('update_post/<int:pk>/', views.PostUpdate.as_view()),
path('create_post/', views.PostCreate.as_view()),
path('tag/<str:slug>/',views.tag_page),
path('<int:pk>/',views.PostDetail.as_view()),
# path('<int:pk>/',views.single_post_page), 사용 안 함(PostDetail로 변경되었음)
path('category/<str:slug>/',views.category_page),
# views에 있는 category_page로 이동시킴
# https://project-ztsct.run.goorm.io/blog/category/programming
# programming만 분리해서 view.py의 category_page로 보냄
path('<int:pk>/new_comment/', views.new_comment),
# path('', views.index), Class 형태로 변환되었기 때문에 주석 처리한다.
path('',views.PostList.as_view()),
# post_list.html 형태로 만든다.
]
- admin.py -
from django.contrib import admin
from markdownx.admin import MarkdownxModelAdmin
from .models import Post, Category, Tag, Comment
# ---------------------------------------------------------------------------
admin.site.register(Post, MarkdownxModelAdmin)
# Register your models here.
admin.site.register(Comment)
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name', )}
# 자동으로 slug 생성
# 태그
class TagAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name', )}
# post와 Category를 가지고 오기
admin.site.register(Category, CategoryAdmin)
admin.site.register(Tag, TagAdmin)
목록보기
sungyong 1 year, 11 months ago
혹시 아래와 같은 문제가 아닌지 확인해보세요.
https://doitdjango.com/board/qna/209/
https://doitdjango.com/board/qna/258/
Updated: Dec. 22, 2022, 10:54 p.m.
Leave a Comment: