📚 stacks
안녕하세요, 반갑습니다! ConnectME 서비스를 만든 사회화지원소 입니다.
저희가 만든 서비스에 대한 사용자 피드백을 받아보고자 이렇게 인사를 드리게
되었습니다.
서비스 소개
ConnectME는 친구 만들기 서비스입니다. 새 친구를 사귀고 싶거나, 맛집에 가고 취미생활을 하고 싶은데 같이 갈 사람이 없는 분들을 위해 만들게 되었습니다.
가깝거나 성격이 비슷한 친구들을 소개받고, 1:1 채팅을 통해 소통할 수 있습니다. 또한 모일 장소를 추천받아 모임을 생성할 수 있고, 익명으로 고민상담도 할 수 있는 서비스입니다.
안녕하세요, 반갑습니다! ConnectME 서비스를 만든 사회화지원소 입니다.
저희가 만든 서비스에 대한 사용자 피드백을 받아보고자 이렇게 인사를 드리게
되었습니다.
서비스 소개
ConnectME는 친구 만들기 서비스입니다. 새 친구를 사귀고 싶거나, 맛집에 가고 취미생활을 하고 싶은데 같이 갈 사람이 없는 분들을 위해 만들게 되었습니다.
가깝거나 성격이 비슷한 친구들을 소개받고, 1:1 채팅을 통해 소통할 수 있습니다. 또한 모일 장소를 추천받아 모임을 생성할 수 있고, 익명으로 고민상담도 할 수 있는 서비스입니다.
안녕하세요, 반갑습니다! ConnectME 서비스를 만든 사회화지원소 입니다.
저희가 만든 서비스에 대한 사용자 피드백을 받아보고자 이렇게 인사를 드리게
되었습니다.
서비스 소개
ConnectME는 친구 만들기 서비스입니다. 새 친구를 사귀고 싶거나, 맛집에 가고 취미생활을 하고 싶은데 같이 갈 사람이 없는 분들을 위해 만들게 되었습니다.
가깝거나 성격이 비슷한 친구들을 소개받고, 1:1 채팅을 통해 소통할 수 있습니다. 또한 모일 장소를 추천받아 모임을 생성할 수 있고, 익명으로 고민상담도 할 수 있는 서비스입니다.
친구찿기 메인페인지 입니다.
프로필 메뉴 버튼이 있는데요 메뉴 클릭하면 프로필 정보를 수정이 가능합니다.
리스트 형식으로 고민상담거리를 게시판처럼 이용 할 수 있습니다.
models.py
from django.db import models
from user.models import User
"""상담 게시글 모델입니다."""
class Counsel(models.Model):
user = models.ForeignKey(User, verbose_name="작성자", on_delete=models.CASCADE)
title = models.CharField(max_length=50, verbose_name="제목")
content = models.TextField(verbose_name="내용")
like = models.ManyToManyField(User, related_name='counsel_like', verbose_name="좋아요")
created_at = models.DateTimeField(verbose_name="작성일" , auto_now_add=True,)
updated_at = models.DateTimeField(verbose_name="수정일" , auto_now=True)
"""상담 댓글 모델입니다."""
class CounselComment(models.Model):
user = models.ForeignKey(User, verbose_name="댓글작성자", on_delete=models.CASCADE, related_name="counsel_comment_user")
counsel= models.ForeignKey(Counsel, on_delete=models.CASCADE, related_name="counsel_comment_counsel")
content = models.TextField(verbose_name="내용")
like = models.ManyToManyField(User, related_name='counsel_comment_like', verbose_name="좋아요")
created_at = models.DateTimeField(verbose_name="작성일" , auto_now_add=True,)
updated_at = models.DateTimeField(verbose_name="수정일" , auto_now=True)
"""상담 답글 모델입니다."""
class CounselReply(models.Model):
user = models.ForeignKey(User, verbose_name="댓글작성자", on_delete=models.CASCADE, related_name="counsel_reply_user")
counsel= models.ForeignKey(Counsel, on_delete=models.CASCADE)
comment = models.ForeignKey(CounselComment, verbose_name="댓글", on_delete=models.CASCADE, related_name="reply")
content = models.TextField(verbose_name="내용")
like = models.ManyToManyField(User, related_name='counsel_reply_like', verbose_name="좋아요")
created_at = models.DateTimeField(verbose_name="작성일" , auto_now_add=True,)
updated_at = models.DateTimeField(verbose_name="수정일" , auto_now=True)
Counsel: 상담 게시글 모델입니다.
모델기능을 간단하게 요약을 해봅니다.
user: 작성자를 나타내는 외래키 입니다.
.
title: 상담 게시글의 제목을 알려줍니다.
content: 상담 게시글의 내용 입니다.
like: 사용자들이 좋아요 누르는 갯수만큼 나옵니다.
created_at:게시글의 작성일을 알려주는 기능입니다.
update_at:게시글의 수정일을 알려주는 기능입니다.
CounselComment: 상담 게시글에 대한 댓글을 나타내는 모델입니다.
user: 댓글을 나타내는 외래 키 입니다.
counsel:댓글에 속한 상담 게시글을 나타내는 외래 키 입니다.
content: 댓글 내용을 담는 텍스트입니다.
like: 사용자들이 좋아요 누르는 갯수만큼 나옵니다.
created_at:댓글의 작성일을 알려주는 기능입니다.
update_at:댓글의 수정일을 알려주는 기능입니다.
CounselReply: 상담 댓글에 대한 모델입니다.
user: 답글 작성자를 나타내는 외래 키 입니다.
counsel:답글이 속한 상담 게시글을 나타내는 외래 키 입니다.
content: 답글 내용을 담는 텍스트입니다.
like: 사용자들이 좋아요 누르는 갯수만큼 나옵니다.
created_at:답글의 작성일을 알려주는 기능입니다.
update_at:답글의 수정일을 알려주는 기능입니다.
from rest_framework import serializers
from .models import (
Counsel,
CounselComment,
CounselReply
)
""" 대댓글 """
'''대댓글 작성'''
class CounselReplyCreateSerializer(serializers.ModelSerializer):
class Meta:
model = CounselReply
fields = ("content",)
extra_kwargs = {
"content": {
"error_messages": {
"required": "댓글을 입력해주세요.",
"blank": "댓글을 입력해주세요.",
}
},
}
'''대댓글'''
class CounselReplySerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
reply_like_count = serializers.SerializerMethodField()
comment_created_at = serializers.DateTimeField(
format="%y-%m-%d %H:%M", read_only=True
)
def get_reply_like_count(self, obj):
return obj.like.count()
def get_user(self, obj):
return {"nickname": obj.user.nickname, "pk": obj.user.pk}
class Meta:
model = CounselReply
fields = "__all__"
""" 댓글 """
class CounselCommentSerializer(serializers.ModelSerializer):
reply = CounselReplySerializer(many=True)
user = serializers.SerializerMethodField()
comment_like_count = serializers.SerializerMethodField()
comment_created_at = serializers.DateTimeField(
format="%y-%m-%d %H:%M", read_only=True
)
def get_user(self, obj):
return {"account": obj.user.account, "pk": obj.user.pk, "nickname": obj.user.nickname}
def get_comment_like_count(self, obj):
return obj.like.count()
class Meta:
model = CounselComment
fields = "__all__"
'''댓글 작성'''
class CounselCommentCreateSerializer(serializers.ModelSerializer):
class Meta:
model = CounselComment
fields = ("content",)
extra_kwargs = {
"content": {
"error_messages": {
"required": "댓글을 입력해주세요.",
"blank": "댓글을 입력해주세요.",
}
},
}
""" 글 작성, 상세, 수정 """
'''글 리스트'''
class CounselListSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(format="%Y년 %m월 %d일 %H시 %M분")
def get_user(self, obj):
return {"account": obj.user.account, "pk": obj.user.pk, "nickname": obj.user.nickname}
class Meta:
model = Counsel
fields = "__all__"
'''글 작성, 수정'''
class CounselCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Counsel
exclude = ['user', 'like', 'created_at', 'updated_at']
extra_kwargs={
"title": {
"error_messages": {
"blank": "제목을 입력해주세요",
}
},
"content": {
"error_messages": {
"blank": "내용을 입력해주세요",
},
},
}
'''글 상세'''
class CounselDetailSerializer(serializers.ModelSerializer):
created_at = serializers.DateTimeField(format="%Y년 %m월 %d일 %H시 %M분")
updated_at = serializers.DateTimeField(format="%Y년 %m월 %d일 %H시 %M분")
user = serializers.SerializerMethodField()
counsel_comment_counsel = CounselCommentSerializer
def get_user(self, obj):
return {"account": obj.user.account, "pk": obj.user.pk, "nickname": obj.user.nickname}
class Meta:
model = Counsel
fields = "__all__"
CounselReplyCreateSerializer: 대댓글 작성을 위한 Serializer 클래스입니다. CounselReply 모델과 연결되어 있으며, content 필드를 입력 받습니다.
CounselReplySerializer: 대댓글 정보를 나타내기 위한 Serializer 클래스입니다. CounselReply 모델과 연결되어 있으며, user, reply_like_count, comment_created_at 필드를 반환합니다. get_reply_like_count 메서드는 대댓글의 좋아요 수를 계산하고, get_user 메서드는 대댓글 작성자의 닉네임과 pk를 반환합니다.
CounselCommentSerializer: 댓글 정보를 나타내기 위한 Serializer 클래스입니다. CounselComment 모델과 연결되어 있으며, reply, user, comment_like_count, comment_created_at 필드를 반환합니다. reply 필드는 CounselReplySerializer를 사용하여 해당 댓글의 대댓글을 시리얼라이즈합니다. get_user 메서드는 댓글 작성자의 계정, pk, 닉네임을 반환하고, get_comment_like_count 메서드는 댓글의 좋아요 수를 계산합니다.
CounselCommentCreateSerializer: 댓글 작성을 위한 Serializer 클래스입니다. CounselComment 모델과 연결되어 있으며, content 필드를 입력 받습니다.
CounselListSerializer: 상담 게시글 목록을 나타내기 위한 Serializer 클래스입니다. Counsel 모델과 연결되어 있으며, user, created_at 필드를 반환합니다. get_user 메서드는 게시글 작성자의 계정, pk, 닉네임을 반환합니다.
CounselCreateSerializer: 상담 게시글 작성 및 수정을 위한 Serializer 클래스입니다. Counsel 모델과 연결되어 있으며, title, content를 입력 받습니다. 일부 필드는 제외되고, 추가적인 유효성 검사 메시지가 설정되어 있습니다.
CounselDetailSerializer: 상담 게시글 상세 정보를 나타내기 위한 Serializer 클래스입니다. Counsel 모델과 연결되어 있으며, 모든 필드를 반환합니다. created_at, updated_at 필드는 지정된 형식으로 변환되고, user 필드는 게시글 작성자의 계정, pk, 닉네임을 반환합니다. counsel_comment_counsel 필드는 CounselCommentSerializer를 사용하여 해당 게시글의 댓글을 시리얼라이즈합니다.
from rest_framework.views import APIView
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated,AllowAny
from rest_framework.pagination import PageNumberPagination
from .models import(
Counsel,
CounselComment,
CounselReply,
)
from .serializers import(
CounselListSerializer,
CounselCreateSerializer,
CounselDetailSerializer,
CounselCommentSerializer,
CounselCommentCreateSerializer,
CounselReplySerializer,
CounselReplyCreateSerializer,
)
'''페이지네이션 시작'''
class CounselPagination(PageNumberPagination):
page_size = 15
'''페이지네이션 끝'''
'''게시글 시작'''
class CounselView(APIView):
permission_classes = [AllowAny]
pagination_class = CounselPagination()
def get_permissions(self):
if self.request.method == "POST":
return [IsAuthenticated(),]
else:
return super(CounselView, self).get_permissions()
'''글목록'''
def get(self, request):
counsels = Counsel.objects.all().order_by('-id')
paginator = self.pagination_class
result_page = paginator.paginate_queryset(counsels, request)
total_items = paginator.page.paginator.count
serializer = CounselListSerializer(result_page, many=True)
return Response({"counsel": serializer.data, "total-page": total_items}, status=status.HTTP_200_OK)
'''글작성'''
def post(self, request):
serializer = CounselCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CounselDetailView(APIView):
permission_classes = [AllowAny]
def get_permissions(self):
if self.request.method == "PUT" or self.request.method == "DELETE":
return [IsAuthenticated(),]
else:
return super(CounselDetailView, self).get_permissions()
'''글상세'''
def get(self, request, counsel_id):
counsel = get_object_or_404(Counsel, id=counsel_id)
counsel_serializer = CounselDetailSerializer(counsel)
return Response({'counsel':counsel_serializer.data}, status=status.HTTP_200_OK)
'''글수정'''
def put(self, request, counsel_id):
counsel = get_object_or_404(Counsel, id=counsel_id)
if counsel.user == request.user:
serializer = CounselCreateSerializer(counsel, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status.HTTP_200_OK)
else:
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
else:
return Response({"message":"권한이 없습니다."}, status.HTTP_403_FORBIDDEN)
'''글삭제'''
def delete(self, request, counsel_id):
counsel = get_object_or_404(Counsel, id=counsel_id)
if counsel.user == request.user:
counsel.delete()
return Response({'message': '삭제 완료'},status=status.HTTP_200_OK)
else:
return Response({"message":"권한이 없습니다."}, status.HTTP_403_FORBIDDEN)
'''작성한 게시글 모아보기'''
class MyCreateCounselView(APIView):
permission_classes = [IsAuthenticated]
pagination_class = CounselPagination
def get(self, request):
counsel = Counsel.objects.filter(user=request.user).order_by('-id')
paginator = self.pagination_class()
result_page = paginator.paginate_queryset(counsel, request)
total_items = paginator.page.paginator.count
serializer = CounselListSerializer(result_page, many=True)
return Response({"counsel": serializer.data, "total-page": total_items}, status.HTTP_200_OK)
'''게시글 좋아요'''
class CounselLikeView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, counsel_id):
counsel = get_object_or_404(Counsel, id=counsel_id)
if request.user in counsel.like.all():
counsel.like.remove(request.user)
counsel_like = counsel.like.count()
return Response({"message":"좋아요 취소", "counsel_like":counsel_like}, status=status.HTTP_200_OK)
else:
counsel.like.add(request.user)
counsel_like = counsel.like.count()
return Response({"message":"좋아요", "counsel_like":counsel_like}, status=status.HTTP_202_ACCEPTED)
""" 게시글 끝 """
""" 댓글 시작 """
class CounselCommentView(APIView):
permission_classes = [AllowAny]
def get_permissions(self):
if self.request.method == "PUT" or self.request.method == "DELETE":
return [IsAuthenticated(),]
elif self.request.method == "POST":
return [IsAuthenticated(),]
else:
return super(CounselCommentView, self).get_permissions()
'''댓글리스트'''
def get(self, request, counsel_id):
counsel = get_object_or_404(Counsel, id=counsel_id)
comments = counsel.counsel_comment_counsel.all()
serializer = CounselCommentSerializer(comments, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
'''댓글작성'''
def post(self, request, counsel_id):
serializer = CounselCommentCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, counsel_id=counsel_id)
return Response({"meesage":"작성완료"}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CounselCommentDetailView(APIView):
'''댓글수정'''
def put(self, request, counsel_id, counsel_comment_id):
comment = get_object_or_404(CounselComment, id=counsel_comment_id)
if comment.user == request.user:
serializer = CounselCreateSerializer(comment, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({"meesage":"수정완료"}, status.HTTP_200_OK)
else:
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
else:
return Response({"message":"권한이 없습니다."}, status.HTTP_403_FORBIDDEN)
'''댓글삭제'''
def delete(self, request, counsel_id, counsel_comment_id):
comment = get_object_or_404(CounselComment, id=counsel_comment_id)
if request.user == comment.user:
if comment.reply.all():
serializer = CounselReplyCreateSerializer(comment, {"content":"삭제된 댓글 입니다."} )
if serializer.is_valid():
serializer.save(content="삭제된 댓글 입니다.")
return Response(serializer.data, status=status.HTTP_204_NO_CONTENT)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
comment.delete()
return Response({'message': '삭제 완료'},status=status.HTTP_200_OK)
else:
return Response({"message":"권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
class CounselCommentLikelView(APIView):
'''댓글 좋아요'''
def post(self, request, counsel_id, counsel_comment_id):
counselcomment = get_object_or_404(CounselComment, id=counsel_comment_id)
if request.user in counselcomment.like.all():
counselcomment.like.remove(request.user)
comment_like = counselcomment.like.count()
return Response({"message": "댓글 좋아요 취소", "comment_like":comment_like}, status=status.HTTP_200_OK)
else:
counselcomment.like.add(request.user)
comment_like = counselcomment.like.count()
return Response({"message": "댓글 좋아요", "comment_like":comment_like}, status=status.HTTP_202_ACCEPTED)
""" 댓글 끝 """
""" 대댓글 시작 """
class CounselReplyView(APIView):
permission_classes = [AllowAny]
def get_permissions(self):
if self.request.method == "PUT" or self.request.method == "DELETE":
return [IsAuthenticated(),]
elif self.request.method == "POST":
return [IsAuthenticated(),]
else:
return super(CounselReplyView, self).get_permissions()
'''대댓글 리스트'''
def get(self, request, counsel_id, counsel_comment_id):
reply = CounselReply.objects.all()
serializer = CounselReplySerializer(reply, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
'''대댓글 작성'''
def post(self, request, counsel_id, counsel_comment_id):
serializer = CounselReplyCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, counsel_id=counsel_id, comment_id=counsel_comment_id)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CounselReplyDetailView(APIView):
'''대댓글 수정'''
def put(self, request, counsel_id, counsel_reply_id):
reply = get_object_or_404(CounselReply, id=counsel_reply_id)
if request.user == reply.user:
serializer = CounselReplyCreateSerializer(reply, request.data)
if serializer.is_valid():
serializer.save()
return Response({"message":"성공."}, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response({"message":"권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
'''대댓글 삭제'''
def delete(self, request, counsel_id, counsel_reply_id):
reply = get_object_or_404(CounselReply, id=counsel_reply_id)
if request.user == reply.user:
reply.delete()
return Response({"message":"삭제완료"},status=status.HTTP_200_OK)
else:
return Response({"message":"권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
class CounselReplyLikeView(APIView):
permission_classes = [IsAuthenticated]
'''대댓글 좋아요'''
def post(self, request, counsel_id, counsel_reply_id):
counselreply = get_object_or_404(CounselReply, id=counsel_reply_id)
if request.user in counselreply.like.all():
counselreply.like.remove(request.user)
reply_like = counselreply.like.count()
return Response({"message": "좋아요 취소", "reply_like":reply_like}, status=status.HTTP_200_OK)
else:
counselreply.like.add(request.user)
reply_like = counselreply.like.count()
return Response({"message": "좋아요", "reply_like":reply_like}, status=status.HTTP_202_ACCEPTED)
""" 대댓글 끝 """
CounselView: 게시글 목록을 조회하고, 새로운 게시글을 작성합니다.
CounselDetailView: 특정 게시글의 상세 정보를 조회하고, 게시글을 수정하거나 삭제합니다.
MyCreateCounselView: 특정 사용자가 작성한 게시글을 조회합니다.
CounselLikeView: 게시글에 좋아요를 추가하거나 취소합니다.
CounselCommentView: 특정 게시글에 대한 댓글 목록을 조회하고, 새로운 댓글을 작성합니다.
CounselCommentDetailView: 특정 댓글을 수정하거나 삭제합니다. 댓글에 대한 대댓글이 있는 경우 대댓글 내용을 수정하여 댓글을 삭제한 것처럼 처리합니다.
CounselCommentLikelView: 댓글에 좋아요를 추가하거나 취소합니다.
CounselReplyView: 특정 댓글에 대한 대댓글 목록을 조회하고, 새로운 대댓글을 작성합니다.
CounselReplyDetailView: 특정 대댓글을 수정하거나 삭제합니다.
CounselReplyLikeView: 대댓글에 좋아요를 추가하거나 취소합니다.
만남의 광장 카드 리스트입니다.
간단하게 핫플렉스 보겠습니다.
친구도 만나고 지역 정보들에 맛집 정보들을 알 수 있게 정보를 만들었습니다.
크롤링으로 작업을 하고 그 데이터에 맞게 프런트를 입혔습니다.
슬라이드 형식으로 부드럽게 슬라이드해서 사진을 볼 수 있습니다 몰론 프런트지만