Serializers in Django REST framework

Serializers allow complex data such as querysets and model instances to be converted into native Python data types, which can then be easily rendered into JSON, XML, or other content types. Serializers also provide deserialization, which converts parsed data back to complex types after first validating the incoming data.
To put it simply, the server returns data (json format) through the API, and converts the non-json format to json. This is the serialization process. The
browser submits the data to the server, and the server converts the json format to non-json and stores it in the database, which is deserialization. change

The serialization classes in the REST framework are very similar to Django's Form and ModelForm classes. We provide a Serializer class that provides a powerful, generic way to control the output of responses, and a ModelSerializer class that provides an efficient shortcut for creating serializations that handle model instances and querysets.

1. Declare the serialization class

First create a simple object for example:

from datetime import datetime
class Comment(object):
    def __init__(self, email, content, created=None):
        self.email = email
        self.content = content
        self.created = created or datetime.now()
comment = Comment(email='[email protected]', content='foo bar')

Declare a serialization class that you use to serialize and deserialize data corresponding to Comment objects.
Declaring a serialization class looks very similar to declaring a form:

from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

2. Serialized objects

Comments or lists of comments can now be serialized using the CommentSerializer. Likewise, using the Serializer class looks a lot like using the Form class.

serializer = CommentSerializer(comment)
serializer.data
# {'email': '[email protected]', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

At this point the model instance has been converted to a Python native data type. To complete the serialization process, the data is rendered into json.

from rest_framework.renderers import JSONRenderer
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"[email protected]","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

3. Deserialize objects

Deserialization is similar. First we parse a stream into a Python native data type...

from django.utils.six import BytesIO
from rest_framework.parsers import JSONParser
stream = BytesIO(json)
data = JSONParser().parse(stream)

We then restore these native data types into a validated data dictionary.

serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': '[email protected]', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}

4. Save the instance

If you want to be able to return a complete object instance based on validated data, you need to implement one or both of the .create() and .update() methods. For example:

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

If the object instance corresponds to a Django model, you also need to ensure that these methods save the object to the database. If Comment were a Django model, these methods might look like this:

 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

Now, when deserializing data, we can call .save() to return an object instance based on the validated data.

comment = serializer.save()

Calling .save() will create a new instance or update an existing one, depending on whether an existing instance was passed when instantiating the serialized class:

# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)

Both the .create() and .update() methods are optional. You can implement neither, or one or both, depending on the use case of your serialization class.

Pass additional properties to .save()

Sometimes you'll want your view code to inject additional data when saving the instance. This additional data may contain the current user, the current time, or any other information that is not part of the requested data.

serializer.save(owner=request.user)

When calling .create() or .update(), any additional keyword arguments will be included in the validated_data argument.

Directly override .save().

In some cases, the .create() and .update() method names may not make sense. For example, in a Contact Form, we might not create a new instance but send an email or other message.

In these cases, you may choose to override .save() directly as it is more readable and meaningful.

for example:

class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()
    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)

Note that in the above case, the serializer .validated_data property must be accessed directly.

5. Verification

When deserializing data, you always need to call is_valid() before trying to access the validation data, or save the object instance. If any validation errors occurred, the .errors property will contain a dictionary representing the error messages. For example:

serializer = CommentSerializer(data={
    
    'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': [u'Enter a valid e-mail address.'], 'created': [u'This field is required.']}

Each key in the dictionary is a field name, and the value is the error message (list of strings) corresponding to that field. The non_field_errors key may also be present and will list any general validation errors. The names of the non_field_errors keywords can be customized using NON_FIELD_ERRORS_KEY (set in the settings file).

When deserializing a list of items, errors are returned as a list of dictionaries representing each deserialized item.

An exception is thrown during data validation.
The is_valid() method takes an optional raise_exception flag, which will cause it to raise a serializers.ValidationError exception if there is a validation error.
These exceptions are automatically handled by the default exception handler provided by the REST framework and will return HTTP 400 Bad Request by default

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

Field-Level Validation
You can specify custom field-level validation by adding the .validate_<field_name> method to your Serializer subclass. These are similar to the .clean_<field_name> method on Django forms.
These methods have only one parameter, which is the field value that needs to be verified.

Your validate_<field_name> method should return the validation value or raise serializers.ValidationError.

from rest_framework import serializers
class BlogPostSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()
    def validate_title(self, value):
        """
        Check that the blog post is about Django.
        """
        if 'django' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value

Object-Level Validation
If you want to perform additional validation on multiple fields, add a method named .validate() to your Serializer subclass. This method has only one parameter, which is a dictionary of field-values. It should raise a ValidationError if necessary, or just return the validated value. For example:

from rest_framework import serializers
class EventSerializer(serializers.Serializer):
    description = serializers.CharField(max_length=100)
    start = serializers.DateTimeField()
    finish = serializers.DateTimeField()
    def validate(self, data):
        """
        Check that the start is before the stop.
        """
        if data['start'] > data['finish']:
            raise serializers.ValidationError("finish must occur after start")
        return data

Validators
Individual fields on a serializer can contain validators by declaring them on the field instance, for example:

def multiple_of_ten(value):
    if value % 10 != 0:
        raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
    score = IntegerField(validators=[multiple_of_ten])
    ...

Serialization classes can also contain reusable validators that apply to the entire field dataset. These validators are included by declaring them inside the Meta class as follows:

class EventSerializer(serializers.Serializer):
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
    date = serializers.DateField()
    class Meta:
        # Each room only has one event per day.
        validators = UniqueTogetherValidator(
            queryset=Event.objects.all(),
            fields=['room_number', 'date']
        )

Guess you like

Origin blog.csdn.net/javascript_good/article/details/132672405