๐Ÿ“’ [ TIL ] 2022.06.21_44์ผ์ฐจ # Django Rest Framework (5)

๋ฌธ๋ช…์ฃผยท2022๋…„ 6์›” 21์ผ
0
post-thumbnail

[ 2022-06-21 (ํ™”) ์˜ค๋Š˜์˜ TIL ]

[ Today Learn ]

  • validator
  • custom validator

โœ๏ธ ๋‚ด๊ฐ€ ๋ฐฐ์šด๊ฒƒ, ์–ป์€๊ฒƒ

  • serializer ์‹ฌํ™”
    serializer๋Š” ๋ฐ์ดํ„ฐ ์ง๋ ฌํ™” ์™ธ์—๋„ data validation, create, update ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • validator
    serializer์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Meta class ๋‚ด๋ถ€ field์— ํฌํ•จ๋˜์–ด ์žˆ๋Š” ํ•ญ๋ชฉ์— ๋งž๊ฒŒ validate๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค

๐Ÿงฉ ์ ์šฉ ์˜ˆ์‹œ

# views.py
from user.serializers import UserSerializer

...

class UserView(APIView):
    def post(self, request):
        # serializer์˜ data ์ธ์ž์—๋Š” model๋กœ ์ง€์ • ๋œ ํ…Œ์ด๋ธ”์˜ field:value๋ฅผ dictionary๋กœ ๋„˜๊ฒจ์ค€๋‹ค.
        user_serializer = UserSerializer(data=request.data)
        # serializer validator๋ฅผ ํ†ต๊ณผํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ .is_valid()๊ฐ€ False๋กœ return๋œ๋‹ค.
        if user_serializer.is_valid():
            # validator๋ฅผ ํ†ต๊ณผํ–ˆ์„ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ ์ €์žฅ
            user_serializer.save()
            return Response({"message": "์ •์ƒ"}, status=status.HTTP_200_OK)
        
        # .errors์—๋Š” validator์— ์‹คํŒจํ•œ ํ•„๋“œ์™€ ์‹คํŒจ ์‚ฌ์œ ๊ฐ€ ๋‹ด๊ฒจ์ ธ ์žˆ๋‹ค.
        return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

# sample request.data
"""
{
    "username": "new_user",
    "password": "MyL0ve1yP@ssw0rd",
    "fullname": "myname",
    "userprofile": {
        "introduction": "์ž๊ธฐ์†Œ๊ฐœ์ž…๋‹ˆ๋‹ค.",
        "birthday": "2000-1-01",
        "age": 30
    },
    "trash": "zczxcvx"
}
"""
  • serializer์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜๋“ค

๐Ÿงฉ ์ ์šฉ ์˜ˆ์‹œ

class UserSerializer(serializers.ModelSerializer):
    # ์™ธ๋ž˜ ํ‚ค ๊ด€๊ณ„์— ์žˆ๋Š” ํ•„๋“œ์˜ required๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค˜์•ผ ํ•œ๋‹ค.
    userprofile = UserProfileSerializer(required=False) # default : True
    ...
    class Meta:
        ...
        # ๊ฐ ํ•„๋“œ์— ํ•ด๋‹นํ•˜๋Š” ๋‹ค์–‘ํ•œ ์˜ต์…˜ ์ง€์ •
        extra_kwargs = {
            # write_only : ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์“ฐ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด ์ค€๋‹ค.
            # ์“ฐ๊ธฐ ์ „์šฉ์œผ๋กœ ์„ค์ • ๋œ ํ•„๋“œ๋Š” ์ง๋ ฌํ™” ๋œ ๋ฐ์ดํ„ฐ์—์„œ ๋ณด์—ฌ์ง€์ง€ ์•Š๋Š”๋‹ค.
            'password': {'write_only': True}, # default : False
            'email': {
                # error_messages : ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์„ค์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.
                'error_messages': {
                    # required : ๊ฐ’์ด ์ž…๋ ฅ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ๋ณด์—ฌ์ง€๋Š” ๋ฉ”์„ธ์ง€
                    'required': '์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.',
                    # invalid : ๊ฐ’์˜ ํฌ๋งท์ด ๋งž์ง€ ์•Š์„ ๋•Œ ๋ณด์—ฌ์ง€๋Š” ๋ฉ”์„ธ์ง€
                    'invalid': '์•Œ๋งž์€ ํ˜•์‹์˜ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'
                    },
                    # required : validator์—์„œ ํ•ด๋‹น ๊ฐ’์˜ ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.
                    'required': False # default : True
                    },
            }
  • view์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜๋“ค

๐Ÿงฉ ์ ์šฉ ์˜ˆ์‹œ

# serializer์˜ ์ธ์ž์— object๋ฅผ ๋„ฃ์–ด ์ง๋ ฌํ™” ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
user = request.user
return Response(UserSerializer(user).data, status=status.HTTP_200_OK)

# object์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ queryset์„ ์ธ์ž๋กœ ๋„ฃ์–ด ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ง๋ ฌํ™” ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
hobbys = Hobby.objects.all()
# queryset์„ ์ธ์ž๋กœ ๋„ฃ์„ ๊ฒฝ์šฐ many=True ์„ค์ • ํ•„์š”ํ•˜๋‹ค.
return Response(HobbySerializer(hobbys, many=True).data, status=status.HTTP_200_OK)

# partial์„ True๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ required field์— ๋Œ€ํ•œ validation์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.
# ์ฃผ๋กœ ์ผ๋ถ€ ํ•„๋“œ๋ฅผ update ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.
user_serializer = UserSerializer(data=request.data, partial=True)

# raise_exception์„ True๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ validation์„ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ–ˆ์„ ๋•Œ exception์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
user_serializer = UserSerializer(data=request.data, raise_exception=True)
  • custom validator
    1) custom validator๋Š” validator ์ดํ›„์— ๋™์ž‘ํ•œ๋‹ค.
    2) custom validator๋Š” validator์™€ ๋ณ„๊ฐœ๋กœ ๋™์ž‘ํ•œ๋‹ค.
    3) validator๋Š” ๋ฐ์ดํ„ฐ์˜ requierd, invalid ๋“ฑ์„ ํŒ๋‹จํ•˜๊ณ  custom validator์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” validation์„ ์ถ”๊ฐ€๋กœ ๊ฒ€์ฆ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿงฉ ์ ์šฉ ์˜ˆ์‹œ

class UserSerializer(serializers.ModelSerializer):
    ...
    # validate ํ•จ์ˆ˜ ์„ ์–ธ ์‹œ serializer์—์„œ ์ž๋™์œผ๋กœ ํ•ด๋‹น ํ•จ์ˆ˜์˜ validation์„ ํ•ด์คŒ
    def validate(self, data):
        # custom validation pattern
        if data.get("userprofile", {}).get("age", 0) < 12:
            # validation์— ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•  ๊ฒฝ์šฐ ValidationError class ํ˜ธ์ถœ
            raise serializers.ValidationError(
                    # custom validation error message
                    detail={"error": "12์„ธ ์ด์ƒ๋งŒ ๊ฐ€์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."},
                )

        # validation์— ๋ฌธ์ œ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ data return
        return data

๐ŸŒฑ ๋Š๋‚€ ์ 

serializer๋ฅผ ๋ฐฐ์šฐ๋ฉด์„œ ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค๊ณผ ๋ฌธ๋ฒ•๋“ฑ์„ ์‚ดํŽด๋ดค๋Š”๋ฐ, ๊ทธ๋™์•ˆ ๋ณด์ง€ ๋ชปํ–ˆ๋˜ ๊ธฐ๋Šฅ ๋“ค์ด ๋งŽ์•„์„œ ํ•œ ๋ฒˆ์— ์Šต๋“ํ•˜๋Š”๋ฐ์—๋Š” ๋ฌด๋ฆฌ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์•ž์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งˆ๋‹ค ์ง์ ‘ ์ฐพ์•„๋ณด๋ฉด์„œ ์ต์ˆ™ํ•ด์ ธ์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณ„์† ๋ฐฐ์šฐ๋Š” ๊ฒŒ ์ถ•์ ๋ ๋•Œ๋งˆ๋‹ค ์†Œํ™”ํ•ด์•ผ ํ•  ์–‘์ด ๋งŽ์•„์ง€๊ฒŒ ๋˜๋ฉด์„œ ๋ฒ…์ฐจ๊ธฐ๋„ ํ•˜์ง€๋งŒ, ๊ณ„์† ๋ณต์Šตํ•˜๊ณ  ๋งŽ์ด ์ ‘ํ•ด์„œ ์ต์ˆ™ํ•ด์ง€๋Š”๊ฒƒ๋งŒ์ด ์‹ค๋ ฅ์„ ๊ธฐ๋ฅผ ์ˆ˜ ์žˆ๋Š” ๊ธธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

profile
ํ•˜๋ฃจ ํ•œ๊ฑธ์Œ์”ฉ ๊พธ์ค€ํžˆ ๋‚˜์•„๊ฐ€๋Š” ๊ฐœ๋ฐœ์ž๐Ÿ™†โ€โ™€๏ธ https://github.com/Moonmooj

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด