feat: Post 비공개 기능 추가
Some checks failed
Build And Test / build-and-push (push) Has been cancelled

- Post 모델에 is_private 필드 추가
- 비공개 게시글은 작성자만 목록/상세에서 조회 가능
- 공개/비공개 토글 기능 지원

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-25 12:56:05 +09:00
parent c02851e4d3
commit d87d70997b
5 changed files with 59 additions and 7 deletions

View 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),
),
]

View File

@ -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']

View File

@ -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):

View File

@ -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

View File

@ -1 +1 @@
v0.0.13 v0.0.14