댓글 API

  • url로 보낸 id 값을 받아야 한다.
  • 댓글을 조회하면 user는 email
  • todo는 title을 보여준다.

 

 

(app - models.py) 추가하기

class Comment(models.Model):
    user = models.ForeignKey(Users, on_delete=models.CASCADE)
    a_todo = models.ForeignKey(Todos, on_delete=models.CASCADE)
    content = models.CharField(max_length=256)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.content)

 

 

(app - urls.py) 추가하기

urlpatterns = [
    path('<int:todo_id>/comment/', views.CommentView.as_view(), name='comment_view'),
    path('<int:todo_id>/comment/<int:comment_id>/', views.CommentDetailView.as_view(), name='comment_detail_view'),
]

 

 

(app - serializers.py)

class CommentSerialize(serializers.ModelSerializer):
    #시리얼라이저에서 메서드를 호출하여 필드의 값을 결정한다
    user = serializers.SerializerMethodField()
    todo = serializers.SerializerMethodField()
    
    #여기 메서드 호출
    def get_user(self, obj):
        return obj.user.email
    
    def get_todo(self, obj):
        return obj.a_todo.title
    
    class Meta:
        model = Comment
        # a_todo를 뺀 나머지 필드
        exclude = ('a_todo', )

class CommentCreateSerialize(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ['content', ]


class TodoSerialize(serializers.ModelSerializer):
    # 추가하기
    # 역참조
    # todo 게시글에서도 comment를 보여줌
    comment_set = CommentSerialize(many = True)

 

 

(app - views.py)

class CommentView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, todo_id):
        comment = Comment.objects.all()
        serialize = CommentSerialize(comment, many=True)
        return Response(serialize.data, status=status.HTTP_200_OK)
    
    def post(self, request, todo_id):
        serialize = CommentCreateSerialize(data=request.data)
        todo = Todos(id=todo_id)
        if serialize.is_valid():
            serialize.save(user=request.user, a_todo=todo)
            return Response(serialize.data, status=status.HTTP_201_CREATED)
        else:
            return Response(f'${serialize.errors}', status=status.HTTP_400_BAD_REQUEST)

class CommentDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def put(self, request, todo_id, comment_id):
        comment = get_object_or_404(Comment, id=comment_id)
        if request.user == comment.user:
            serialize = CommentSerialize(comment, data=request.data)
            if serialize.is_valid():
                serialize.save()
                return Response({"수정됨":serialize.data}, status=status.HTTP_200_OK)
        else:
            return Response({'message':'권한이 없습니다'},status=status.HTTP_400_BAD_REQUEST)
    
    def delete(self, request, todo_id, comment_id):
        comment = get_object_or_404(Comment, id=comment_id)
        if request.user == comment.user:
            comment.delete()
            return Response('댓글 삭제 완료', status=status.HTTP_204_NO_CONTENT)
        else:
            return Response({'message':'권한이 없습니다'},status=status.HTTP_400_BAD_REQUEST)

 

 

Todo 리스트

  • 게시글을 전부 불러와 보여질 페이지
  • 여러개의 시리얼라이즈를 불러올 때 many=True를 사용

(app - models.py )

from django.db import models
from user.models import Users


class Todos(models.Model):
    user = models.ForeignKey(Users, on_delete=models.CASCADE)
    title = models.CharField(max_length=50)
    # 파일 찾기 기능을 고려해 시간대별 저장
    image = models.ImageField(blank=True, upload_to='%Y/%m/%d/')
    is_complete = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    completion_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return str(self.title)

 

(app - views.py)

from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from todo.models import Todos      
from todo.serializers import TodoSerialize


class TodoView(APIView):
    # 로그인한 유저인지 확인
    permission_classes = [IsAuthenticated]
    def get(self, request):
        todo = Todos.objects.all()
        # 여러개의 시리얼라이즈를 불러올 때 many=True를 사용
        serialize = TodoSerialize(todo, many=True)
        return Response(serialize.data, status=status.HTTP_200_OK)

 

(app - serializers.py)

from rest_framework import serializers
from todo.models import Todos

class TodoSerialize(serializers.ModelSerializer):
    class Meta:
        model = Todos
        fields = '__all__'

 

 

 

 

 

 

Todo 생성

  • 게시글 작성은 title과 image 데이터만 받음
  • user는 데이터를 실어온 시리얼라이즈에 로그인한 유저의 정보를 추가하여 저장

 

(app - views.py)

from todo.serializers import TodoCreateSerialize

class TodoView(APIView):
    def post(self, request):
        serialize = TodoCreateSerialize(data=request.data)
        if serialize.is_valid():
            # user를 저장하지 않으면 에러남
            serialize.validated_data['user'] = request.user
            serialize.save()
            # 또는 아래와 같이 유저를 저장할 수 있다.
            # serialize.save(user=request.user)
            return Response(serialize.data, status=status.HTTP_201_CREATED)
        else:
            return Response({'message':f'${serialize.errors}'}, status=status.HTTP_400_BAD_REQUEST)

 

(app - serializers.py)

class TodoCreateSerialize(serializers.ModelSerializer):
    class Meta:
        model = Todos
        fields = ['title', 'image']

 

https://www.django-rest-framework.org/api-guide/fields/

 

 

 

 

 

Todo 수정, 삭제하기

  • 개인페이지의 열람, 수정, 삭제는 로그인한 유저와 게시글을 쓴 유저의 정보가 일치할 때만 가능
  • 객체가 존재하지 않으면 404 에러를 발생

 

(app - views.py)

class TodoDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, todo_id):
        # 객체가 존재하지 않으면 404에러를 발생
        todo = get_object_or_404(Todos, id=todo_id)
        if request.user == todo.user:
            serialize = TodoSerialize(todo)
            return Response(serialize.data, status=status.HTTP_200_OK)
        else:
            return Response({'message':'권한이 없습니다.'}, status=status.HTTP_400_BAD_REQUEST)
    
    def put(self, request, todo_id):
        todo = get_object_or_404(Todos, id=todo_id)
        if request.user == todo.user:
            serialize = TodoCreateSerialize(todo, data=request.data)
            if serialize.is_valid():
                serialize.save()
                return Response(serialize.data, status=status.HTTP_200_OK)
            else:
                return Response({'message':'데이터가 옳바르지 않습니다.'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response({'message':'권한이 없습니다.'}, status=status.HTTP_400_BAD_REQUEST)   
    
    def delete(self, request, todo_id):
        todo = get_object_or_404(Todos, id=todo_id)
        if request.user == todo.user:
            todo.delete()
            return Response({'message':'삭제 완료'},status=status.HTTP_204_NO_CONTENT)
        else:
            return Response({'message':'권한이 없습니다.'}, status=status.HTTP_400_BAD_REQUEST)

 

 

 

 

 

 

 

 

+) 시리얼라이즈를 활용( get_user 메소드 )하여 user를 보여줄 때 email로 보여줄 수 있다.

from rest_framework import serializers
from todo.models import Todos


class TodoSerialize(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()

    # user attribute(변수) 앞에 get을 사용
    # obj는 해당 Article
    def get_user(self, obj):
        # return 값이 user라는 attribute 값에 들어감
        return obj.user.email
        
    class Meta:
        model = Todos
        fields = '__all__'

 

스태틱, 미디어 폴더

  • 장고에서 스태틱, 미디어 폴더를 사용하기 위해서는 Pillow를 설치해야 한다.
  • 미디어 폴더의 경우 .gitignore에 등록하면 깃에 업로드 되는 것을 피할 수 있다.
  • runserver(개발환경)에서 media 파일 서빙을 권장하지 않는다.
  • 이 때문에 urlpatterns을 작성하면 파일이 서빙된다.

 

https://docs.djangoproject.com/en/4.2/howto/static-files/

 

 

pip install Pillow

 

 

(settings.py)

STATIC_ROOT = BASE_DIR / 'static'
STATIC_URL = '/static/'

MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'

 

 

(urls.py)

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

 

 

 

 

 

 이미지 등록하기

  • postman에서 이미지 등록시 form-data를 사용

 

 

 

 

 

 

 

 

 

 

 

 

+) access 토큰을 enviroments에 등록하여 쓸 수 있다.

        *단, 처음 작성할 때와 달리 Current value가 자동으로 변경되지 않으므로, Initial value, Current value  둘 다 입력해야한다.

'Python > Django' 카테고리의 다른 글

[DRF] 11. 댓글 API(두 개의 모델 참조)  (0) 2023.04.26
[DRF] 10. 게시글 API  (0) 2023.04.26
[DRF] 08.5 토큰 주기설정, permission  (0) 2023.04.26
[DRF] 08. Payload 커스텀  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26

토큰 주기 설정 

 

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

 

 

(settings.py)

    배포할 때는 access 토큰 평균 5~30분 정도

from datetime import timedelta

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=100),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "ROTATE_REFRESH_TOKENS": False,
    "BLACKLIST_AFTER_ROTATION": False,
    "UPDATE_LAST_LOGIN": False,

    "ALGORITHM": "HS256",
    "SIGNING_KEY": SECRET_KEY,
    "VERIFYING_KEY": "",
    "AUDIENCE": None,
    "ISSUER": None,
    "JSON_ENCODER": None,
    "JWK_URL": None,
    "LEEWAY": 0,

    "AUTH_HEADER_TYPES": ("Bearer",),
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",

    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",

    "JTI_CLAIM": "jti",

    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),

    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}

 

 

 

 

permission

 

(app-views.py)

from rest_framework import permissions

class MockView(APIView):
    #로그인 확인
    permission_classes = [permissions.IsAuthenticated]
    def get(self, request):
        return Response('get 요청')

 

refresh 토큰으로 access 토큰 받기

    Body에 refresh 토큰을 입력하면 access 토큰을 받을 수 있다.

 

'Python > Django' 카테고리의 다른 글

[DRF] 10. 게시글 API  (0) 2023.04.26
[DRF] 09. 스태틱, 미디어 폴더 세팅  (0) 2023.04.26
[DRF] 08. Payload 커스텀  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25

Payload 커스텀

  • JWT Payload에 모델에서 작성한 필드를 추가하기

 

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/customizing_token_claims.html

 

(app-views.py)

from users.serializers import CustomTokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

 

 

(app-serializers.py)

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        token['bio'] = user.bio
        token['name'] = user.name
        token['age'] = user.age
        token['gender'] = user.gender

        return token

 

 

(app-urls.py) 수정하기

urlpatterns = [
    path('api/token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
]

 

'Python > Django' 카테고리의 다른 글

[DRF] 09. 스태틱, 미디어 폴더 세팅  (0) 2023.04.26
[DRF] 08.5 토큰 주기설정, permission  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25
[DRF] 06. User / UserManager  (0) 2023.04.24

+ Recent posts