DRF๋ก ์์ฑํ API์ POST Request๋ฅผ ๋ณด๋์ ์ View์ Serializer์์ ์ด๋ค ํ๋ฆ์ผ๋ก ์ฝ๋๊ฐ ํ๋ฌ๊ฐ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์ฑ๋๋์ง ๋๋ฆ๋๋ก ์ ๋ฆฌํด๋ณด์๋ค.
# snippets/models.py
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
class Meta:
ordering = ['created']
# snippets/serializers.py
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Snippet.objects.create(**validated_data)
# snippets/views.py
from rest_framework.mixins import CreateModelMixin
from rest_framework.viewsets import GenericViewSet
from .serializers import SnippetSerializer
class SnippetViewSet(GenericViewSet, CreateModelMixin):
serializer_class = SnippetSerializer
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
์์ ๊ฐ์ models.py , serializers.py , views.py๋ก Snippet์ Createํ๋ API๋ฅผ ๋ง๋ค์๋ค๊ณ ๊ฐ์ ํด๋ณด์.
{
"title": "title",
"code": "code",
"language": "python",
"style": "friendly"
}
์ฐ๋ฆฌ๋ ์์ ๊ฐ์ JSON Request๋ฅผ ํตํด POST Method๋ก Django์ ์์ฒญ์ ๋ณด๋ผ ๊ฒ์ด๋ค.
1. Views์ create ํจ์ ์์ผ๋ก ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ๋ค.
class SnippetViewSet(GenericViewSet, CreateModelMixin):
serializer_class = SnippetSerializer
def create(self, request, *args, **kwargs):
print(request.data)
return super().create(request, *args, **kwargs)
{'title': 'title', 'code': 'code', 'language': 'python', 'style': 'friendly'}
print ๋ฌธ์ผ๋ก create ํจ์์ request.data๋ฅผ ์ฐ์ด๋ณด๋ฉด ์ฐ๋ฆฌ๊ฐ ์์ฒญํ ๋ฐ์ดํฐ๊ฐ ์ ์ฐํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ด request์์ ๋ด๊ธด ๋ฐ์ดํฐ๋ CreateModelMixin ์ create ํจ์๋ก ์ด๋ํ๊ฒ ๋๋ค.
2. CreateModelMixin ํจ์ ์์ผ๋ก ๋ฐ์ดํฐ๋ ์ด๋ํ๋ค.
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
CreateModelMixin ํจ์ ์์ ๋ค์ฌ๋ค๋ณด๋ฉด ์์ ๊ฐ์ด ์๊ฒผ๋ค. ๋จผ์ get_serializer ํจ์๋ฅผ ํตํด์ serializer๋ฅผ ๊ฐ์ง๊ณ ์ค๊ฒ ๋๋ค. ๊ฐ์ง๊ณ ์จ serializer์ is_valid()๋ฅผ ํตํด์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๋ค perform_create ํจ์๋ฅผ ํตํด์ serializer๋ฅผ ์ ์ฅํ๊ฒ ๋๋ค. is_valid()์์๋
# snippets/serializers.py
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(
required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(
choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
def validate_title(self, data):
print(data)
if data == "error":
raise serializers.ValidationError("Invalid Value.")
return data
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Snippet.objects.create(**validated_data)
DRF์ Serializer Class๋ฅผ ๋ณด๋ฉด to_internal_value ๋ผ๋ ํจ์๊ฐ ์๋ค.
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, Mapping):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='invalid')
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
์ด ์ฝ๋๋ฅผ ๋ณด๋ฉด serializer์ ์๋ field๋ค์ for ๋ฌธ์ผ๋ก ํ๋ ํ๋ ๊ฒ์ฌํ๋ฉด์ validate_{field.field_name} ์ผ๋ก validate_method๋ฅผ ์ค์ ํด์ฃผ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฆ, ๋ง์ฝ title ์ด๋ผ๋ field๊ฐ ์๋ค๋ฉด validate_title ํจ์๊ฐ ์๋์ง ํ์ธํ๊ณ validate๋ฅผ ์งํํ ํ data๋ฅผ ๋ค์ ๋ฐํํ๋ค.
'Python > ๐ฆ Django' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Django] ํน์ ์กฐ๊ฑด์ ๋ง๋ ๊ฐ์ฒด๊ฐ ์กด์ฌํ๋์ง ํ์ธํด์ผํ ๋ get์ ์จ์ผํ ๊น filter๋ฅผ ์จ์ผํ ๊น? (0) | 2024.03.08 |
---|---|
[Django] ์ฝ๋ฉ ์คํ์ผ (0) | 2023.09.04 |
[Django] Django Custom Command (0) | 2023.09.04 |
[Django] JWT๋ก ๋ก๊ทธ์์์ ๊ตฌํํด๋ณด์ (0) | 2023.09.04 |
[Django] QuerySet ์ดํดํ๊ธฐ - Lazy Loading, Caching, Eager Loading (0) | 2023.09.04 |