๐Ÿ‘ฆ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„/TIL(Today I Learned)

TIL_220617_DRF ๊ฐ•์˜

  • -

DRF ์˜ ๊ฝƒ Serializer ์— ๋Œ€ํ•ด์„œ ๋ฐฐ์šฐ๊ณ ,

 

Serializer ๋กœ ๊ณผ์ œ๋ฅผ ๋ฐ›์•˜๋‹ค.

 

์–ด๋Š์ •๋„ ์ดํ•ด๋ฅผ ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ,

 

์ƒ๊ฐ๋ณด๋‹ค ์ƒ์†๊ณผ ๋‹ค๋ฅธ Serializer ์ถ”๊ฐ€ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด

 

๋๋‚ด ๊ณผ์ œ๋ฅผ ์™„์„ฑํ•  ์ˆ˜ ์—†์—ˆ๋‹ค..

 

๊ทธ๋ž˜๋„ ํ•ด์„ค ๊ฐ•์˜๋ฅผ ํ†ตํ•ด ๋งˆ์ง€๋ง‰๊นŒ์ง€ ์ฐ๋จนํ•ด๋ณด์•˜๋‹ค.

 


์—๋Ÿฌ ๋…ธํŠธ

์‚ฌ์‹ค ์—๋Ÿฌ๋ผ๊ธฐ ๋ณด๋‹ค๋Š” ๋‚ด๊ฐ€ ์‹ค์ˆ˜ํ•œ ๋‚ด์šฉ์ด์ง€๋งŒ, ๋‘ ๋ฒˆ ์‹ค์ˆ˜ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ์ ์–ด๋‘”๋‹ค.

 

<๊ด€๋ฆฌ์ž ๊ณ„์ • ์—๋Ÿฌ>
์›์ธ : 
1) ํƒ€์ž„์–ดํƒ ์‹œ ์™„์ „ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ ์ƒ์„ฑํ•˜๊ณ  ์‹œ์ž‘.
2) ํƒ€์ž„์–ดํƒ 2๋ฒˆ ๋ฌธ์ œ์—์„œ USERNAME_FIELD ๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ๊ณ„์† ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๊ธฐ์ดํ•œ ํ˜„์ƒ
3) ์—๋Ÿฌ ์ฝ”๋“œ๋„ ๋œจ์ง€ ์•Š๊ณ  ๊ณ„์† ์‚ฌ์šฉ์ž ์ด๋ฆ„๋ถ€ํ„ฐ ์ž‘์„ฑํ•˜๋ผ๊ณ  ํ•จ.

ํ•ด๊ฒฐ : AUTH_USER_MODEL = 'user.User'
๊ณ„์ • ๋ชจ๋ธ์„ ์ž์‹ ์ด ์ปค์Šคํ…€ํ•œ ๊ณ„์ • ๋ชจ๋ธ๋กœ ๋ฉ”์ธ์œผ๋กœ ์ง€์ •์„ ๊ผญ ํ•ด์ค˜์•ผ ์žฅ๊ณ ์˜ ๊ธฐ๋ณธ ๋ชจ๋ธ์—์„œ ์ž์‹ ์ด ์ปค์Šคํ…€ํ•œ ๋ชจ๋ธ๋กœ ์ ์šฉ๋˜์–ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
(๊ธฐ๋ณธ์ ์ธ๊ฑด๋ฐ.. ๊ด€๋ฆฌ์ž ๋ชจ๋ธ ์ง€์ •์„ ์•ˆํ•ด์ค€ ์‹ค์ˆ˜.. ใ… )

 

<input ์ด ์ •์ƒ์ ์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ>

    # ๊ธ€ ์ƒ์„ฑ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    def post(self, request):
        user = request.user
        title = request.data.get("title", "")
        contents = request.data.get(<<"contents">>, "")
        category = request.data.get("category", [])

====================================================================

<<< input >>>

{
    "title" : "์•ˆ๋…•ํ•˜์„ธ์š” ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค.",
    <<"contents">> : "๊ธ€ ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค. ์™€์šฐ ๋นก๋นก์ด ์•„์ฃ ์”จ์•ผ!!! ํ˜ธ์šฐ!!!!!!",
    "category" : [4, 5]
}


๋ฆฌํ€˜์ŠคํŠธ๋กœ ๋ฐ›์•„์˜ค๋Š” ํ•„๋“œ๋ช…์€ ๊ผญ ์ž…๋ ฅ๋ฐ์ดํ„ฐ ๋ช…๊ณผ ๊ฐ™์•„์•ผํ•œ๋‹ค.

 


์ฐธ๊ณ  ์ž๋ฃŒ

์ฐธ๊ณ ๊ฐ€ ๋˜์—ˆ๋˜ ์ž๋ฃŒ๋“ค์„ ์ฐพ์•„๋ดค๋‹ค.

 

Serializer ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

์ถœ์ฒ˜ ์œ ํˆฌ๋ธŒ : https://www.youtube.com/watch?v=V4NjlXiu5WI 

 


4์ผ์ฐจ ๊ณผ์ œ

1. blog ์•ฑ์— <๊ฒŒ์‹œ๊ธ€, ์‚ฌ์šฉ์ž, ๋‚ด์šฉ>์ด ํฌํ•จ๋œ comment ํ…Œ์ด๋ธ”์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”

class Comment(models.Model):
    # Article ์— ์ž‘์„ฑํ•œ ์ฝ”๋ฉ˜ํŠธ์˜ ์ถœ์ฒ˜(์ž‘์„ฑ์ž) / CASCADE ๋Œ“๊ธ€์˜ ์ž‘์„ฑ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ํ•จ๊ป˜ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์„ค์ •
    user = models.ForeignKey('user.User', verbose_name="๋Œ“๊ธ€ ์ž‘์„ฑ์ž", on_delete=models.CASCADE)
    # Article ๊ณผ์˜ ๋Œ“๊ธ€ ๊ด€๊ณ„ ์ •์˜ / CASCADE ๊ฒŒ์‹œ๊ธ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ํ•จ๊ป˜ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์„ค์ •
    article = models.ForeignKey(Article, verbose_name="๋Œ“๊ธ€์„ ์ž‘์„ฑํ•œ ๊ธ€", on_delete=models.CASCADE)
    content = models.TextField("๋Œ“๊ธ€ ๋‚ด์šฉ")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.user.username} ๋‹˜์ด ์ž‘์„ฑํ•˜์‹  ๋Œ“๊ธ€์ž…๋‹ˆ๋‹ค."


2. ์™ธ๋ž˜ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์„œ Article, User ํ…Œ์ด๋ธ”๊ณผ ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์ฃผ์„ธ์š”

# Article ์— ์ž‘์„ฑํ•œ ์ฝ”๋ฉ˜ํŠธ์˜ ์ถœ์ฒ˜(์ž‘์„ฑ์ž) / CASCADE ๋Œ“๊ธ€์˜ ์ž‘์„ฑ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ํ•จ๊ป˜ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์„ค์ •
user = models.ForeignKey('user.User', verbose_name="๋Œ“๊ธ€ ์ž‘์„ฑ์ž", on_delete=models.CASCADE)
# Article ๊ณผ์˜ ๋Œ“๊ธ€ ๊ด€๊ณ„ ์ •์˜ / CASCADE ๊ฒŒ์‹œ๊ธ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ํ•จ๊ป˜ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์„ค์ •
article = models.ForeignKey(Article, verbose_name="๋Œ“๊ธ€์„ ์ž‘์„ฑํ•œ ๊ธ€", on_delete=models.CASCADE)


3. admin.py์— comment๋ฅผ ์ถ”๊ฐ€ํ•ด ์ž์œ ๋กญ๊ฒŒ ์ƒ์„ฑ, ์ˆ˜์ • ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์„ธ์š”

from django.contrib import admin
from blog.models import Comment

# Register your models here.
admin.site.register(Comment)


4. serializer๋ฅผ ํ™œ์šฉํ•ด ๋กœ๊ทธ์ธ ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ธฐ๋ณธ ์ •๋ณด์™€ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๋ฆฌํ„ดํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”

class HobbySerializer(serializers.ModelSerializer):

    # ์ด ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ์ž์‹ ์˜ ์ทจ๋ฏธ์™€ ํ•ด๋‹นํ•˜๋Š” ์œ ์ € ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Œ.
    # ์ž์‹ ์ด ์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ ํ•„๋“œ ์ƒ์„ฑ ๊ฐ€๋Šฅ
    same_hobby_users = serializers.SerializerMethodField()
    # SerializerMethodField() ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” get_same_hobby_users ๊ผญ ํ•„์š”
    def get_same_hobby_users(self, obj):
        # obj : hobby model ์˜ obj
        user_list = []
        for user_profile in obj.userprofile_set.all():
            user_list.append(user_profile.user.username)
        
        # return [up.user.username for up in obj.userprofile_set.all()] ์ถ•์•ฝ์‹
        return user_list

    class Meta:
        model = Hobby
        fields = ['name', 'same_hobby_users']

class UserProfileSerializer(serializers.ModelSerializer):

    hobby = HobbySerializer(many=True) # input data queryset ์ผ ๊ฒฝ์šฐ

    class Meta:
        model = UserProfile
        # ๋ถˆ๋Ÿฌ์˜ค๊ณ ์ž ํ•˜๋Š” user ์˜ ๊ธฐ๋ณธ ์ •๋ณด์™€ ์ƒ์„ธ ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
        fields = ['introduction', 'birthday', 'age', 'hobby']
        # __all__ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ถˆํ•„์š”ํ•œ ์ •๋ณด๋„ ํ•จ๊ป˜ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋•Œ๋ฌธ์—
        # ํŠน์ • ์ •๋ณด์— ํ•ด๋‹นํ•˜๋Š” ์ •๋ณด๋งŒ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ง์ ‘ ์„ค์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.


class UserSerializer(serializers.ModelSerializer):

    # object 
    userprofile = UserProfileSerializer()
    
    class Meta:
        model = User
        # ์—ญ์ฐธ์กฐ๋กœ userprofile ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
        fields = ["username", "password", "fullname", "email", "join_date", "userprofile"]


5. 4๋ฒˆ์˜ serializer์— ์ถ”๊ฐ€๋กœ ๋กœ๊ทธ์ธ ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฒŒ์‹œ๊ธ€, ๋Œ“๊ธ€์„ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”

class UserSerializer(serializers.ModelSerializer):

    # object 
    userprofile = UserProfileSerializer()

    # ํ•ด๋‹น ์œ ์ €์˜ ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ
    userarticle = ArticleSerializer(source="article_set" ,many=True)
    
    class Meta:
        model = User
        # ์—ญ์ฐธ์กฐ๋กœ userprofile ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
        fields = ["username", "password", "fullname", "email", "join_date", "userprofile", "userarticle"]


6. blog ์•ฑ์— title / category / contents๋ฅผ ์ž…๋ ฅ๋ฐ›์•„์„œ ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”

 - ๋งŒ์•ฝ title์ด 5์ž ์ดํ•˜๋ผ๋ฉด ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”
 - ๋งŒ์•ฝ contents๊ฐ€ 20์ž ์ดํ•˜๋ผ๋ฉด ๊ฒŒ์‹œ๊ธ€์„ ์ž‘์„ฑํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”
 - ๋งŒ์•ฝ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋ฆฌํ„ดํ•ด์ฃผ์„ธ์š”

    # ๊ธ€ ์ƒ์„ฑ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    def post(self, request):
        user = request.user
        title = request.data.get("title", "")
        contents = request.data.get("contents", "")
        category = request.data.get("category", [])

        # ๊ธ€์ž์ˆ˜ ์กฐ๊ฑด ์ดํ•˜์ผ ๊ฒฝ์šฐ
        if len(title) <= 5:
            return Response({"error" : "ํƒ€์ดํ‹€์€ 5์ž ์ด์ƒ ์ž‘์„ฑํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค."}, status=status.HTTP_400_BAD_REQUEST)
        
        # ๊ธ€์ž์ˆ˜ ์กฐ๊ฑด ์ดํ•˜์ผ ๊ฒฝ์šฐ
        if len(contents) <= 20:
            return Response({"error" : "๊ธ€ ๋‚ด์šฉ์€ 20์ž ์ด์ƒ ์ž‘์„ฑํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค."}, status=status.HTTP_400_BAD_REQUEST)
        
        if not category:
            return Response({"error" : "์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."}, status=status.HTTP_400_BAD_REQUEST)

        article = ArticleModel(
            user = user,
            title = title,
            content = contents
        )
        article.save()
        article.category.add(*category)
        return Response({"message": "์„ฑ๊ณต!"}, status=status.HTTP_200_OK)


7. custom permission class๋ฅผ ํ™œ์šฉํ•ด ๊ฐ€์ž… ํ›„ 3์ผ ์ด์ƒ ์ง€๋‚œ ์‚ฌ์šฉ์ž๋งŒ ๊ฒŒ์‹œ๊ธ€์„ ์“ธ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์„ธ์š”

 - ํ…Œ์ŠคํŠธ ํ•  ๋•Œ์—๋Š” ๊ฐ€์ž… ํ›„ 3๋ถ„ ์ด์ƒ ์ง€๋‚œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒŒ์‹œ๊ธ€์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์„ธ์š”
 - join_date๋Š” datetime field๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”

from rest_framework.permissions import BasePermission
from datetime import timedelta
from django.utils import timezone


class RegisterdMoreThanThreeDaysUser(BasePermission):
    ''' 
    ๊ฐ€์ž…์ผ ๊ธฐ์ค€ 3์ผ ์ด์ƒ ์ง€๋‚œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    '''

    message = '๊ฐ€์ž… ํ›„ 3์ผ ์ด์ƒ ์ง€๋‚œ ์‚ฌ์šฉ์ž๋งŒ ์‚ฌ์šฉํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.'

    def has_permission(self, request, view):
        user = request.user
        # ํ•จ์ถ•์‹ ์กฐ๊ฑด 1) ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž์ธ๊ฐ€ ์กฐ๊ฑด 2) ๊ฐ€์ž…์ผ ๊ธฐ์ค€ 3์ผ์ด ์ง€๋‚ฌ๋Š”๊ฐ€
        return bool(user.is_authenticated and request.user.join_date < (timezone.now() - timedelta(days=3)))
        
        ====================================================================
        
        class ArticleView(APIView):
        	permission_classes = [RegisterdMoreThanThreeDaysUser]   # ์ปค์Šคํ…€ permissions



 

'๐Ÿ‘ฆ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„ > TIL(Today I Learned)' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

TIL_220621_DRF ๊ฐ•์˜  (0) 2023.01.01
TIL_220620_DRF ๊ฐ•์˜  (0) 2023.01.01
TIL_220616_DRF ๊ฐ•์˜  (0) 2023.01.01
TIL_220615_DRF ๊ฐ•์˜  (0) 2023.01.01
TIL_220614_ํŒ€ ํ”„๋กœ์ ํŠธ django  (0) 2023.01.01
Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.