Serializers
serializers λ querysetκ³Ό λͺ¨λΈ μΈμ€ν΄μ€μ κ°μ 볡μ‘ν λ°μ΄ν°λ₯Ό JSON
, XML
λλ λ€λ₯Έ 컨ν
μΈ μ νμΌλ‘ μ½κ² λ λλ§ν μ μλ python κΈ°λ³Έ λ°μ΄ν° μ νμΌλ‘ λ³νν΄μ€λ€. λν deserialization μ μ 곡νμ¬, λ€μ΄μ€λ λ°μ΄ν°μ μ ν¨μ±μ μ²μ νμΈν νμ ꡬ문 λΆμμ΄ λ λ°μ΄ν°λ₯Ό λ³΅ν© νμμΌλ‘ λ€μ λ³νν μ μλ€.
REST νλ μμν¬μ serializers λ Djangoμ Form
, modelForm
ν΄λμ€μ λ§€μ° μ μ¬νκ² μλνλ€. serializers λ ModelSerializer
, Serializer
ν΄λμ€λ₯Ό μ 곡νλ€.
μ¬μ©μ μ djangorestframework
κ° μ€μΉλμ΄μλμ§ νμΈν΄μΌνλ€.
$ pip list
Package Version
------------------- -------
Django 2.1.7
djangorestframework 3.9.2
pip 19.0.3
pytz 2018.9
setuptools 40.6.2
Serialzers μ μΈ
κ°λ¨ν μλ₯Όλ€κΈ° μν΄μ κ°μ²΄ νκ°λ₯Ό μμ±νλ€.
# models.py
from django.db import models
from datetime import datetime
# Create your models here.
class Comment(models.Model):
email = models.CharField(max_length=100,blank=False)
content = models.TextField()
created_at = models.DateTimeField(default=datetime.now)
$ ./manage.py shell
>>> from quickstart.models import Comment
>>> from datetime import datetime
>>> c=Comment(email="test@test.com", content="testsetstsetset")
>>> c.save()
>>> Comment.objects.all()
<QuerySet [<Comment: Comment object (1)>, <Comment: Comment object (2)>]>
>>>
comment
κ°μ²΄μ ν΄λΉνλ λ°μ΄ν°λ₯Ό serializer, deserializerν ν μ μλ serializerλ₯Ό μ μΈνλ€.
# appνλ‘μ νΈμ serializers.py μΆκ°
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Serializing Objects
μμ±ν Serializer
ν΄λμ€λ₯Ό μ¬μ©νμ¬ ν΄λΉ κ°μ²΄λ₯Ό serializingν μ μλ€.
>>> from quickstart.serializers import CommentSerializer
>>> c = Comment.objects.get(id=1)
>>> serializer = CommentSerializer(c)
>>> serializer.data
{'email': 'test@test.com', 'content': 'testsetstsetset', 'created_at': '2019-10-08T07:28:15.082464Z'}
μ΄ μμ μμλ λͺ¨λΈ μΈμ€ν΄μ€λ₯Ό νμ΄μ¬ κΈ°λ³Έ λ°μ΄ν° μ νμΌλ‘ λ³νν κ²μ΄λ€.
JSON λ°μ΄ν°λ‘ λ³ννκΈ° μν΄μλ JSONRenderer
λ₯Ό μ΄μ©ν΄ jsonμΌλ‘ λ°κΏμ€λ€.
>>> from rest_framework.renderers import JSONRenderer
>>> json = JSONRenderer().render(serializer.data)
>>> json
b'{"email":"test@test.com","content":"testsetstsetset","created_at":"2019-10-08T07:28:15.082464Z"}'
Deserializing Objects
serializingκ³Ό μ μ¬νλ€. μ°μ jsonλ°μ΄ν°λ₯Ό νμ΄μ¬ λ°μ΄ν° νμμΌλ‘ parsingν νμ κΈ°λ³Έ λ°μ΄ν°λ₯Ό κ²μ¦λ λ°μ΄ν°λ‘ 볡μνλ€.
>>> from django.utils.six import BytesIO
>>> from rest_framework.parsers import JSONParser
>>> stream = BytesIO(json)
>>> data = JSONParser().parse(stream)
>>> data
{'email': 'test@test.com', 'content': 'testsetstsetset', 'created_at': '2019-10-08T07:28:15.082464Z'}
>>> serializer = CommentSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('email', 'test@test.com'), ('content', 'testsetstsetset'), ('created_at', datetime.datetime(2019, 10, 8, 7, 28, 15, 82464, tzinfo=<UTC>))])
Return Instance
μμ ν κ°μ²΄ μΈμ€ν΄μ€λ₯Ό λ°ννκΈ° μν΄μλ create()
, update()
λ©μλλ₯Ό ꡬνν΄μ object instance λ°νμ΄ κ°λ₯νλ€.
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
def create(self, validated_data):
return Comment(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email',instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
return instance
κ°μ²΄ μΈμ€ν΄μ€κ° λͺ¨λΈκ³Ό μΌμΉνλ κ²½μ°μλ μλμ κ°μ΄ κ°μ²΄λ₯Ό λ°μ΄ν°λ² μ΄μ€μ μ μ₯λλλ‘ ν΄μΌνλ€.
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
# λͺ¨λΈ κ°μ²΄μ μΌμΉνλ κ²½μ°
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.email = validated_data.get('email', instance.email)
instance.content = validated_data.get('content', instance.content)
instance.created = validated_data.get('created', instance.created)
instance.save()
return instance
λ°μ΄ν°λ deserializingν λ .save()
λ₯Ό νΈμΆνμ¬ μ ν¨μ±μ΄ κ²μ¬λ λ°μ΄ν°λ₯Ό κΈ°λ°μΌλ‘ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό λ°νν μ μλ€.
>>> deserializer = CommentSerializer(data=serializer.data)
>>> comment = deserializer.save()
>>> comment
<Comment: Comment object (3)>
μ¬κΈ°μ save()
λ instanceκ° μ‘΄μ¬νλ©΄ updateλ₯Ό μ‘΄μ¬νμ§μμΌλ©΄ createλ₯Ό ν΄μ€λ€.
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
μΈμ€ν΄μ€λ₯Ό μ μ₯νλ μμ μ λ·° μ½λκ° λ°μ΄ν°λ₯Ό μΆκ°ν μ μμ΄μΌνλ©°, μ΄ μΆκ° λ°μ΄ν°μλ λ€λ₯Έ μ λ³΄κ° ν¬ν¨λ μ μλ€.
>>> serializer.save(writer=request.user)
μΆκ°λ λ°μ΄ν°λ .create()
νΉμ .update()
κ° νΈμΆλ λ validated_dataμ ν¬ν¨λλ€.
Validation
λ°μ΄ν°λ₯Ό deserializerν λ μ ν¨μ±μ΄ κ²μ¦λ λ°μ΄ν°μ μ κ·ΌνκΈ° μ μ is_valid()
λ₯Ό νΈμΆνκ±°λ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό μ μ₯ν΄μΌνλ€.
>>> deserializer = CommentSerializer(data={'email':'admin@test.com', 'content':'This is test'})
>>> deserializer.save()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/jeongdaye/.pyenv/versions/restful/lib/python3.7/site-packages/rest_framework/serializers.py", line 179, in save
'You must call `.is_valid()` before calling `.save()`.'
AssertionError: You must call `.is_valid()` before calling `.save()`.
>>> deserializer.is_valid()
False
>>> deserializer.errors
{'created_at': [ErrorDetail(string='This field is required.', code='required')]}
λ§μ½μ is_valid()
κ° FalseλΌλ©΄, .errors()
λ₯Ό ν΅ν΄μ κ²°κ³Ό μ€λ₯λ©μΈμ§λ₯Ό νμΈν μ μλ€.
>>> deserializer.is_valid(raise_exception=True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/jeongdaye/.pyenv/versions/restful/lib/python3.7/site-packages/rest_framework/serializers.py", line 243, in is_valid
raise ValidationError(self.errors)
rest_framework.exceptions.ValidationError: {'created_at': [ErrorDetail(string='This field is required.', code='required')]}
raise_exception=True
νλκ·Έλ₯Ό μ¬μ©ν΄ serializers.validationError
μμΈλ₯Ό λ°μμν¬ μ μλ€.
Field λ 벨 κ²μ¦
validate_field
serializer μλΈ ν΄λμ€μ .validate_<field_name>
λ©μλλ₯Ό μΆκ°ν΄ custom field μ ν¨μ± κ²μ¦μ μ§μ ν μ μλ€.
import re
emailRegex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'
class CommentSerializer(serializers.Serializer):
email = serializers.CharField()
content = serializers.CharField()
created_at = serializers.DateTimeField()
def validate_email(self, value):
if(re.search(eamilRegex, value)):
return value
else:
raise serializers.ValidationError("μ΄λ©μΌ νμμ΄ μλͺ»λμμ΅λλ€.")
>>> from quickstart.serializers import CommentSerializer
>>> from datetime import datetime
>>> serializer = CommentSerializer(data={'email':'asdfsdaf', 'content':'asdfasdfasdfasf', 'created_at': datetime.now()})
>>> serializer.is_valid()
False
>>> serializer.errors
{'email': [ErrorDetail(string='μ΄λ©μΌ νμμ΄ μλͺ»λμμ΅λλ€.', code='invalid')]}
validate
μ¬λ¬ νλμ λν μ ν¨μ± κ²μ¬λ₯Ό νλ €λ©΄ .validate()
λ©μλλ₯Ό μΆκ°νλ©΄λλ€. μ΄ λ©μλλ νλκ°μ dict μλ£νμ λ¨μΌ μΈμλ‘ μ·¨νλ€.
class CommentSerializer(serializers.Serializer):
email = serializers.CharField()
content = serializers.CharField()
created_at = serializers.DateTimeField()
def validate(self, data):
if (len(data['content']) < 10) & (data['created_at'] < timezone.now()):
raise serializers.ValidationError("error")
return data
>>> from quickstart.serializers import CommentSerializer
>>> from datetime import datetime
>>> serializer = CommentSerializer(data={'email':'asdfsdaf', 'content':'asdfasdfasdfasf', 'created_at': datetime.now()})
>>> serializer.is_valid()
True
>>> serializer = CommentSerializer(data={'email':'test@test.com', 'content':'asf', 'created_at': datetime.now()})
>>> serializer.is_valid()
False
>>> serializer.errors
{'non_field_errors': [ErrorDetail(string='error', code='invalid')]}
validators
Serializerμ κ°λ³νλμ validatorsλ₯Ό ν΅ν΄ μ ν¨μ± κ²μ¬λ₯Ό ν μ μλ€.
from rest_framework import serializers
import re
emailRegex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$'
def email_check(value):
if(re.search(emailRegex, value)):
return value
else:
raise serializers.ValidationError("μ΄λ©μΌ νμμ΄ μλͺ»λμμ΅λλ€.")
class CommentSerializer(serializers.Serializer):
email = serializers.CharField(validators=[email_check])
content = serializers.CharField()
created_at = serializers.DateTimeField()
>>> from quickstart.serializers import CommentSerializer
>>> from datetime import datetime
>>> serializer = CommentSerializer(data={'email':'asdfsdaf', 'content':'asdfasdfasdfasf', 'created_at': datetime.now()})
>>> serializer.is_valid()
False
>>> serializer.errors
{'email': [ErrorDetail(string='μ΄λ©μΌ νμμ΄ μλͺ»λμμ΅λλ€.', code='invalid')]}
ModelSerializer
ModelSerializer
ν΄λμ€λ λͺ¨λΈ νλκ° ν¬ν¨λ Serailzer ν΄λμ€λ₯Ό κ°λ¨νκ² λ§λ€ μ μλ€.
λͺ¨λΈμ κΈ°λ°μΌλ‘ μΌλ ¨μ νλκ° μλμΌλ‘ μμ±
unique_together validator
μ κ°μ serializerμ λν validatorλ₯Ό μλ μμ±.create()
μ.update()
μ κ°λ¨ν κΈ°λ³Έ ꡬνμ ν¬ν¨
from rest_framework import serializers
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ('email','content','created_at')
λ§μ½ μ 체 νλλ₯Ό ν¬ν¨νκ³ μΆλ€λ©΄ __all__
μΌλ‘ μμ±μ μ€μ νλ©΄λλ€.
from rest_framework import serializers
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
>>> from quickstart.serializers import CommentSerializer
>>> serializer = CommentSerializer()
>>> print(repr(serializer))
CommentSerializer():
id = IntegerField(label='ID', read_only=True)
email = CharField(max_length=100)
content = CharField(style={'base_template': 'textarea.html'})
created_at = DateTimeField(required=False)
exclude
μμ±μΌλ‘ μ μΈνκ³ μΆμ νλλ§ μ€μ ν μλ μλ€.
from rest_framework import serializers
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
exclude = ('email','content','created')
HyperlinkedModelSerializer
HyperlinkedModelSerializer
ν΄λμ€λ κΈ°λ³Έ ν€κ° μλ κ΄κ³λ₯Ό λνλ΄κΈ° μν΄ νμ΄νΌλ§ν¬λ₯Ό μ¬μ©νλ€λ μ μ μ μΈνκ³ λ ModelSerialzer
ν΄λμ€μ μ μ¬νλ€. κΈ°λ³Έμ μΌλ‘ κΈ°λ³Έ ν€ νλ λμ url
νλκ° ν¬ν¨λλ€.
class CommentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Comment
fields = ('url','id','email', 'content', 'created_at')
>>> from quickstart.serializers import CommentSerializer
>>> serializer = CommentSerializer()
>>> print(repr(serializer))
CommentSerializer():
url = HyperlinkedIdentityField(view_name='comment-detail')
id = IntegerField(label='ID', read_only=True)
email = CharField(max_length=100)
content = CharField(style={'base_template': 'textarea.html'})
created_at = DateTimeField(required=False)
url fieldλ HyperlinkedIdentityFieldλ₯Ό μ¬μ©νλ€.
HyperlinkedModelSerializer
ν΄λμ€λ₯Ό μΈμ€ν΄μ€ν ν λλ νμ¬ request
λ₯Ό serializer 컨ν
μ€νΈμ ν¬ν¨ν΄μΌνλ€.
serializer = AccountSerializer(queryset, context={'request': request})
μ΄λ κ² μ λ¬νλ©΄ μ κ·νλ URLμ μ¬μ©νλ€.
http://api.example.com/accounts/1/
λ§μ½ μλ URLμ μ¬μ©νλ €λ©΄ {'request': None}
μ λͺ
μμ μΌλ‘ μ λ¬νλ©΄λλ€.
/accounts/1
How hyperlinked views are determined
λͺ¨λΈμΈμ€ν΄μ€μ νμ΄νΌλ§ν¬νκΈ° μν΄ μ΄λ€ λ·°λ₯Ό μ¬μ©νλμ§ μλ €μ€μΌνλ€. κΈ°λ³Έμ μΌλ‘ {model_name} -detail
μ€νμΌκ³Ό view μ΄λ¦μ΄ μΌμΉν΄μΌνλ©°, pk
ν€μλ μΈμλ‘ μΈμ€ν΄μ€λ₯Ό μ°Ύλλ€. λ§μ½ λ°λ‘ μ§μ ν΄μ£Όκ³ μΆλ€λ©΄ extra_kwargs
μ€μ μμ view_name
λλ lookup_field
μ΅μ
μ μ€μ νλ©΄λλ€.
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Account
fields = ('account_url', 'account_name', 'users', 'created')
extra_kwargs = {
'url': {'view_name': 'accounts', 'lookup_field': 'account_name'},
'users': {'lookup_field': 'username'}
}
λλ serializerμμ νλλ₯Ό λͺ μμ μΌλ‘ μ€μ ν μ μλ€.
class AccountSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='accounts',
lookup_field='slug'
)
users = serializers.HyperlinkedRelatedField(
view_name='user-detail',
lookup_field='username',
many=True,
read_only=True
)
class Meta:
model = Account
fields = ('url', 'account_name', 'users', 'created')
μ°Έκ³ λ§ν¬
Last updated
Was this helpful?