- Post 모델에 is_private 필드 추가 - 비공개 게시글은 작성자만 목록/상세에서 조회 가능 - 공개/비공개 토글 기능 지원 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
18
blog/migrations/0007_post_is_private.py
Normal file
18
blog/migrations/0007_post_is_private.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.14 on 2026-01-25 03:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('blog', '0006_attachment_batch_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='post',
|
||||||
|
name='is_private',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -25,6 +25,7 @@ class Post(models.Model):
|
|||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
author_id = models.CharField(max_length=150, blank=True, default='')
|
author_id = models.CharField(max_length=150, blank=True, default='')
|
||||||
author_name = models.CharField(max_length=150)
|
author_name = models.CharField(max_length=150)
|
||||||
|
is_private = models.BooleanField(default=False) # 비공개 여부 (True: 작성자만 볼 수 있음)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-created_at']
|
ordering = ['-created_at']
|
||||||
|
|||||||
@ -108,7 +108,8 @@ class PostSerializer(serializers.ModelSerializer):
|
|||||||
'author_id', 'author_name',
|
'author_id', 'author_name',
|
||||||
'created_at', 'updated_at',
|
'created_at', 'updated_at',
|
||||||
'comment_count', 'tags', 'tag_names',
|
'comment_count', 'tags', 'tag_names',
|
||||||
'attachments', 'attachment_ids'
|
'attachments', 'attachment_ids',
|
||||||
|
'is_private'
|
||||||
]
|
]
|
||||||
read_only_fields = ['author_id', 'author_name', 'created_at', 'updated_at']
|
read_only_fields = ['author_id', 'author_name', 'created_at', 'updated_at']
|
||||||
|
|
||||||
@ -178,7 +179,8 @@ class PostListSerializer(serializers.ModelSerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
'id', 'title',
|
'id', 'title',
|
||||||
'author_name', 'created_at', 'updated_at',
|
'author_name', 'created_at', 'updated_at',
|
||||||
'comment_count', 'tags', 'thumbnail'
|
'comment_count', 'tags', 'thumbnail',
|
||||||
|
'is_private'
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_comment_count(self, obj):
|
def get_comment_count(self, obj):
|
||||||
|
|||||||
@ -11,6 +11,7 @@ from rest_framework.response import Response
|
|||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.parsers import MultiPartParser, FormParser
|
from rest_framework.parsers import MultiPartParser, FormParser
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.db.models import Q
|
||||||
from .models import Post, Comment, Tag, Attachment
|
from .models import Post, Comment, Tag, Attachment
|
||||||
from .serializers import PostSerializer, PostListSerializer, CommentSerializer, TagSerializer, AttachmentSerializer
|
from .serializers import PostSerializer, PostListSerializer, CommentSerializer, TagSerializer, AttachmentSerializer
|
||||||
import logging
|
import logging
|
||||||
@ -66,7 +67,25 @@ class PostListView(generics.ListAPIView):
|
|||||||
permission_classes = [permissions.AllowAny]
|
permission_classes = [permissions.AllowAny]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = Post.objects.all()
|
user = self.request.user
|
||||||
|
|
||||||
|
if user.is_authenticated:
|
||||||
|
# 로그인 사용자: 공개 게시글 + 자신의 비공개 게시글
|
||||||
|
user_id = str(getattr(user, 'id', '') or getattr(user, 'email', ''))
|
||||||
|
username = getattr(user, 'username', '') or getattr(user, 'email', '')
|
||||||
|
|
||||||
|
# 자신의 비공개 게시글 조건 (빈 문자열은 제외)
|
||||||
|
private_conditions = Q()
|
||||||
|
if user_id:
|
||||||
|
private_conditions |= Q(is_private=True, author_id=user_id)
|
||||||
|
if username:
|
||||||
|
private_conditions |= Q(is_private=True, author_name=username)
|
||||||
|
|
||||||
|
queryset = Post.objects.filter(Q(is_private=False) | private_conditions)
|
||||||
|
else:
|
||||||
|
# 비로그인 사용자: 공개 게시글만
|
||||||
|
queryset = Post.objects.filter(is_private=False)
|
||||||
|
|
||||||
tag = self.request.query_params.get('tag')
|
tag = self.request.query_params.get('tag')
|
||||||
if tag:
|
if tag:
|
||||||
queryset = queryset.filter(tags__name=tag)
|
queryset = queryset.filter(tags__name=tag)
|
||||||
@ -104,9 +123,21 @@ class PostDetailView(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
return [permissions.AllowAny()]
|
return [permissions.AllowAny()]
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
response = super().retrieve(request, *args, **kwargs)
|
instance = self.get_object()
|
||||||
logger.info(f"Post detail requested. ID: {kwargs.get('pk')}, Title: {response.data.get('title')}")
|
|
||||||
return response
|
# 비공개 게시글은 작성자만 조회 가능
|
||||||
|
if instance.is_private:
|
||||||
|
user = request.user
|
||||||
|
if not user.is_authenticated:
|
||||||
|
raise PermissionDenied("비공개 게시글입니다.")
|
||||||
|
user_id = str(getattr(user, 'id', '') or getattr(user, 'email', ''))
|
||||||
|
username = getattr(user, 'username', '') or getattr(user, 'email', '')
|
||||||
|
if instance.author_id != user_id and instance.author_name != username:
|
||||||
|
raise PermissionDenied("비공개 게시글입니다.")
|
||||||
|
|
||||||
|
serializer = self.get_serializer(instance)
|
||||||
|
logger.info(f"Post detail requested. ID: {kwargs.get('pk')}, Title: {serializer.data.get('title')}")
|
||||||
|
return Response(serializer.data)
|
||||||
|
|
||||||
def perform_update(self, serializer):
|
def perform_update(self, serializer):
|
||||||
instance = serializer.instance
|
instance = serializer.instance
|
||||||
|
|||||||
Reference in New Issue
Block a user