Click to jump to the REST-Framework column directory

Serialized objects are the best way to determine whether to retrieve or request data, eliminating the tedious process of determining the request data and traversing the return response data.

Serializer

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from datetime import datetime

from rest_framework import serializers, settings


class UserSerializer(serializers.Serializer) :
    username = serializers.CharField()
    blog = serializers.URLField(max_length=200)
    created = serializers.DateTimeField()


class User:
    def __init__(self, username, blog, created=None) :
        self.username = username
        self.blog = blog
        self.created = created or datetime.now()


if __name__ == '__main__':
    settings.settings.configure()

    user = User(username='MedusaSorcerer', blog='https://juejin.cn/user/2805609406139950')
    serializer = UserSerializer(user)
    print(serializer.data)
Copy the code

In the above code block, we define a User serialization class, then define a User class that mimics ORM, and pass the User instance object User to the serialized data argument. We can generate a serialized object, and print the.data property of the serialized object to obtain the following data:

{'username': 'MedusaSorcerer'.'blog': 'https://juejin.cn/user/2805609406139950'.'created': 'the 2020-08-10 T09:58:35. 754067'}
Copy the code

You can continue rendering the data as JSON objects:

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from datetime import datetime

from rest_framework import serializers, settings


class UserSerializer(serializers.Serializer) :
    username = serializers.CharField()
    blog = serializers.URLField(max_length=200)
    created = serializers.DateTimeField()


class User:
    def __init__(self, username, blog, created=None) :
        self.username = username
        self.blog = blog
        self.created = created or datetime.now()


if __name__ == '__main__':
    settings.settings.configure()
    from rest_framework.renderers import JSONRenderer

    user = User(username='MedusaSorcerer', blog='https://juejin.cn/user/2805609406139950')
    serializer = UserSerializer(user)
    print(JSONRenderer().render(serializer.data))
Copy the code

Note that when using a script execution call Settings. The Settings. The configure () to obtain the location of the configuration information

After running, you can get characters:

B '{" username ":" MedusaSorcerer ", "blog" : "https://juejin.cn/user/2805609406139950", "created" : "the 2020-08-10 T10:03:36. 741946"}'
Copy the code

deserialization

#! /usr/bin/env python # _*_ Coding: UTF-8 _*_ from datetime import datetime import io from rest_framework import serializers, settings class UserSerializer(serializers.Serializer): username = serializers.CharField() blog = serializers.URLField(max_length=200) created = serializers.DateTimeField() class User: def __init__(self, username, blog, created=None): self.username = username self.blog = blog self.created = created or datetime.now() if __name__ == '__main__': settings.settings.configure() from rest_framework.parsers import JSONParser json = B '{" username ":" MedusaSorcerer ", "blog" : "https://juejin.cn/user/2805609406139950", "created" : "the 2020-08-10 T10:03:36. 741946"}'  stream = io.BytesIO(json) data = JSONParser().parse(stream) serializer = UserSerializer(data=data) if serializer.is_valid(): print(serializer.validated_data) else: print(serializer.errors)Copy the code

Deserialization of saved serialized data is also possible. Note that you need to execute.is_Valid () to determine whether the data complies with the object constraints declared by the serialized class. If False is returned, the serialized object does not comply with the declared object constraints. When True is returned, serializers. Validated_data is used to retrieve serialized data:

rderedDict([('username'.'MedusaSorcerer'), ('blog'.'https://juejin.cn/user/2805609406139950'), ('created', datetime.datetime(2020.8.10.10.3.36.741946)))Copy the code

Serializer. Errors if the constraint does not meet the requirements, use the serializer. Errors command to retrieve the error message:

django.core.exceptions.AppRegistryNotReady: The translation infrastructure cannot be initialized before the apps registry is ready. Check that you don't make non-lazy gettext calls at import time.
Copy the code

In fact, the error message returned during development is a dictionary object, key is the string of fields that failed, value is the list of descriptions that failed to comply with the constraints, and because it does not run in a Django project, there is an error message (ignored).

Save the instance

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from datetime import datetime

from rest_framework import serializers


class UserSerializer(serializers.Serializer) :
    username = serializers.CharField()
    blog = serializers.URLField(max_length=200)
    created = serializers.DateTimeField()

    def create(self, validated_data) :
        return User(**validated_data)

    def update(self, instance, validated_data) :
        instance.username = validated_data.get('username', instance.username)
        instance.blog = validated_data.get('blog', instance.blog)
        instance.created = validated_data.get('created', instance.created)
        return instance


class User:
    def __init__(self, username, blog, created=None) :
        self.username = username
        self.blog = blog
        self.created = created or datetime.now()
Copy the code

If you want to use validated data to return a new instance object, you need to implement either create or Update or both.

In Django-ORm you may need to do one operation to save data (ps: in real development, this is not the case, many operations can be omitted) :

#! /usr/bin/env python # _*_ Coding: UTF-8 _*_ from datetime import datetime from rest_framework import serializers class UserSerializer(serializers.Serializer): username = serializers.CharField() blog = serializers.URLField(max_length=200) created = serializers.DateTimeField() def  create(self, validated_data): return User.objects.create(**validated_data) def update(self, instance, validated_data): instance.username = validated_data.get('username', instance.username) instance.blog = validated_data.get('blog', instance.blog) instance.created = validated_data.get('created', instance.created) instance.save() return instanceCopy the code

The save() method for saving an instance or updating an instance depends on whether you are creating an instance or passing an object:

# no instance object is passed, so this is new
serializer = UserSerializer(data=data)

# pass a user object, so this is updating the user object's data
serializer = UserSerializer(user, data=data)
Copy the code

Validation data

In deserialization you can call the.is_Valid () method of the serialized instance object directly to determine the constraint data, or in development you can use.is_Valid (raise_exception=True) to return an error message to the API caller.

If you need a special judgment on a field, you can use validate_

to make a logical judgment.

is the name of the field you declared in the serialized class.

Ps: You can think of serialized classes as ORM classes, but the concept is completely different and the logic is very similar.

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers

class BlogPostSerializer(serializers.Serializer) :
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()

    def validate_title(self, value) :
        """ Judge the title field """
        if 'medusa' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Medusa")
        return value
Copy the code

Perform logical judgment on multiple fields simultaneously:

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers


class BlogPostSerializer(serializers.Serializer) :
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()
    start = serializers.IntegerField()
    finish = serializers.IntegerField()

    def validate(self, data) :
        """ Determine whether the start and Finish parameters passed comply with size logic """
        if data['start'] > data['finish'] :raise serializers.ValidationError("finish must occur after start")
        return data
Copy the code

You can also use field constraints to declare your judgments directly:

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers


def multiple_of_ten(value) :
    if value % 10! =0:
        raise serializers.ValidationError('Not a multiple of ten')


class GameRecord(serializers.Serializer) :
    score = serializers.IntegerField(validators=[multiple_of_ten])
    ...
Copy the code

You can also declare full field validators:

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator


class EventSerializer(serializers.Serializer) :
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101.102.103.201])
    date = serializers.DateField()

    class Meta:
        validators = [
            # unique validator
            UniqueTogetherValidator(
                queryset=User.objects.all(),
                fields=['username'.'other']]Copy the code

Access the instance and initial data

When you pass an initial object or query set to a serialized instance, the object becomes available for fetching using the.instance property, or None if no initial object is passed.

When data is passed to the serializer instance, the unmodified data is provided as.initial_data, and if the data keyword argument is not passed, the.Initial_data property will not exist.

Part of the update

By default, you must pass values for all declared serialized fields, otherwise the serializer will throw validation errors, in which case you can use the partial argument to allow partial updates.

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers


class UpdateSerializer(serializers.Serializer) :
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101.102.103.201])
    date = serializers.DateField()


UpdateSerializer(user, data={'room_number': 101}, partial=True)
Copy the code

Serialization nesting

What if the property of one serialized object is another serialized object?

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers


class UserSerializer(serializers.Serializer) :
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)


class CommentSerializer(serializers.Serializer) :
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
Copy the code

If nesting has the option to accept None, it should pass required=False to the nested serializer:

class CommentSerializer(serializers.Serializer) :
    user = UserSerializer(required=False)
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
Copy the code

If the nested sequence object is made of multiple pieces of data, pass many=True to nested serialization:

class CommentSerializer(serializers.Serializer) :
    user = UserSerializer(required=False)
    edits = EditItemSerializer(many=True)
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
Copy the code

If the deserialized data does not pass the constraint, an error message is returned to the construction field:

serializer = CommentSerializer(data={'user': {'email': 'foobar'.'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()  # False, email and content could not be verified

Output error data
serializer.errors
# {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}
Copy the code

Example of nested object handling

#! /usr/bin/env python
# _*_ Coding: UTF-8 _*_
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer) :
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ['username'.'email'.'profile']

    def create(self, validated_data) :
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user
Copy the code

Serialize multiple objects

queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
Copy the code

Serializer. Data value:

[{'id': 0.'title': 'The electric kool-aid acid test'.'author': 'Tom Wolfe'},
    {'id': 1.'title': 'If this is a man'.'author': 'Primo Levi'},
    {'id': 2.'title': 'The wind-up bird chronicle'.'author': 'Haruki Murakami'}]Copy the code

Additional context links

In some cases, you may need to provide an additional context for the serializer in addition to the object to be serialized.

A common situation is if you are using a serializer that contains hyperlink relationships, requiring the serializer to have access to the current request so that it can correctly generate a fully qualified URL.

You can provide any other context by passing the context parameter when instantiating the serializer:

serializer = AccountSerializer(account, context={'request': request})
serializer.data

{
	'id': 6.'owner': 'denvercoder9'.'created': datetime.datetime(2013.2.12, 09, 44.56.678870), 
    'details': 'http://example.com/accounts/6/details'
}
Copy the code