MVMT 2023. 1. 1. 01:17

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