Serialization Component of rest_framework

What is rest_framework serialization?

When writing a project that does not separate the front and back ends:

We have form components to help us do data validation

We have template syntax, and queryset objects extracted from the database do not need to be reformatted artificially.

When we write front-end and back-end separation projects:

We need to do our own data validation

We need to manually transfer the data format, because cross-platform data transmission uses json strings and cannot directly transfer jsonqueryset objects.

 

At this point, you have to think about the original django has such amazing components, then rest_framework will also have such components? Well, yes!

This is the serialization component of rest_framework. Let's take a look at it.

 

How do I use rest_framework serialization components?

First we need to import several modules from rest_framework

from rest_framework.serializers import Serializer,ModelSerializer
from rest_framework import serializers
Serializer is a native serialization component of rest_framework
Model Serializer is a rest_framework that encapsulates a layer of serialized components on the basis of native serialized components.

Usage: 1. When serializing components with our rest_framework, our view layer must write view classes instead of view functions.

2. We need to write a class for each model table to inherit Serailizer or ModelSerailizer classes.

When we need to serialize or deserialize data in view class, we need to instantiate serialized data in our defined class and call. data to get serialized or validated data.

 

Native Serializer usage:

Using our code in detail, we set up a django project to create a new myserializer file in app01, which contains the serialized classes we defined.

Look at the project application catalogue

 

 

Routing Layer

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # /books/When acquiring all books, /book/1/ Representation pair id Operate for 1 book
    url(r'^book/(?P<id>\w+)/$|(?P<type>books)/$', views.Book.as_view()),

    # Access to all publishing houses
    url(r'^publish/$', views.Publishs.as_view()),

    # Operating on a publishing house
    url(r'^publish/(?P<id>\w+)/$', views.Publish.as_view()),

    # author author Some of them are not written yet.
]

 

Model Layer

from django.db import models

# Create your models here.
from django.contrib.auth.models import User,AbstractUser


class UserInfo(AbstractUser):
    phone = models.CharField(max_length=15)
    avatar = models.FileField(upload_to='static/avatar',default=None)


class Book(models.Model):
    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=10,decimal_places=2)
    publish_time = models.DateField(null=True)
    authors = models.ManyToManyField(to='Author')
    publish = models.ForeignKey(to="Publish")
    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=64)
    choices = ((0, 'male'), (1, 'female'), (2, 'secrecy'))
    sex = models.IntegerField(choices=choices)
    info = models.CharField(null=True,max_length=255)

    def __str__(self):
        return self.name


class Publish(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(null=True,max_length=15)
    address = models.CharField(null=True,max_length=255)

    def __str__(self):
        return self.name

 

 

Serialization component layer

from rest_framework import serializers
from app01 import models

"""
//Use steps:
1,New serialized class, inheritance Serializer
2,One-to-one fields defined in the class and corresponding to the model table
    -The names of the classes can be changed and need to be serializers.CharField()Specified in parentheses source=A field, suggested mapping relationship
    -The field of the foreign key relationship can be used serializers.SerializerMethodField(),It needs to be fixed underneath. get_The method of field name,
        //Here you can write specific logic, and the final result is the result of the field.
3,The parent class needs to be overridden when new data is added create Method, logic is implemented by oneself, can refer to the following BookSerilizers Implemented in a class create Method
4,The parent class needs to be overridden when modifying data update Method, logic is implemented by oneself, can refer to the following BookSerilizers Implemented in a class update Method
5,When these configurations are completed, calls can be instantiated in view classes, serialized, and validated when deserialized.
"""


class PublishSerilizers(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=32)
    phone = serializers.CharField(max_length=15)
    address = serializers.CharField(max_length=255)


class AuthorSerilizers(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=32)
    sex = serializers.CharField() 
    info = serializers.CharField(max_length=255)


class BookSerilizers(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)   #read_only Refers to the current field read-only, the front end can not be passed  write_only This field is not returned to the front-end, but new and modified front-end must be transferred.
    title = serializers.CharField(max_length=64)
    price = serializers.DecimalField(max_digits=8,decimal_places=2)
    publish_time = serializers.DateField()
    # publish = serializers.CharField(source="publish.name") # The source parameter can specify which field name is associated with the current displayed field name in the model table. When specified, the current name cannot be the same as the corresponding field name in the database.
    publish = serializers.SerializerMethodField(allow_null=True)  # SerializerMethodField The way, and then the following definition get_The method of the field name, you can write the logical code in the method and return the value you want to get.
    def get_publish(self,obj):  # There obj Bizhuan, obj Is the current looped data object
        res = PublishSerilizers(instance=obj.publish)  # Serialize the current data object association publish Corresponding data records in tables
        return res.data

    authors = serializers.SerializerMethodField(allow_null=True)
    def get_authors(self,obj):
        authors_list = obj.authors.all()  # author and book It's a many-to-many relationship, so it's necessary..all()Get all the records. That's it. ORM Method
        res = AuthorSerilizers(instance=authors_list,many=True)  #Since multiple records are serialized, specify many=True
        return res.data

    def create(self, validated_data):
        ret = models.Book.objects.create(**validated_data)  # use Django ORM Operation adds data from view layer to database
        return ret

    def update(self, instance, validated_data):  # instance Is the original object of the database    validated_data It's a dictionary with data that needs to be modified after verification.
        instance.name = validated_data.get("name")
        instance.price = validated_data.get("price")
        instance.publish_time = validated_data.get("publish_time")
        instance.publish_id = validated_data.get("publish_id")
        instance.save()     # Save after replacing one by one
        instance.authors.set(validated_data.get("authors")) # Modify multi-to-multi-table records,Modification required set([1,2,4])Form
        return instance

 

View layer

from django.shortcuts import render,HttpResponse

# Create your views here. with Book Information as an example

from rest_framework.views import APIView,Response
from app01 import models
from app01 import myserializers
from app01 import mymodelSer
class  Book(APIView):
    def get(self,request,*args,**kwargs):
        if kwargs.get("type") == 'books': # Judging by the way the routing request comes in, is it to query all the book information or the book information? Here is to look up all the books.
            books = models.Book.objects.all()
            many= True          # Specifies a serialization parameter, if it serializes more than one piece of data True
        elif kwargs.get("id").isdigit():   # If the query carries id,So check out the books.
            books = models.Book.objects.filter(id=kwargs.get("id")).first() #Data Requirements for Serializing Single Data.first()
            many = False     # Specifies a serialization parameter, if it serializes a single data True

        res = myserializers.BookSerilizers(instance=books,many=many)  # Fetch the database queryset Objects are serialized by passing in their own defined serialized classes
        return Response(res.data)
        pass

    def post(self,request,**kwargs):
        response = {"status_code":100,"msg":"New success!"}
        ret = myserializers.BookSerilizers(data=request.data,many=False)   #Deserializing data from the front end
        if ret.is_valid():   # Data validation is done only when this judgment is executed
            print(ret.validated_data)   # The results after verification are used. ret.validated_data,It filters out key-value pairs that do not belong to the model table fields, including those from the front end. publish,authors,Because these two fields are used in the serialized class SerializerMethodField
            ret.validated_data["publish_id"] = request.data.get("publish_id")  #In Creation book Manual calls are required before objects publish The key-value pairs of fields are added, and then created book Record
            res = ret.create(ret.validated_data)  # There create The method is called by us. BookSerilizers The parent class rewritten in it create Method
                                                    # stay create When you have to override the parent class create Method, or you can only use it Django ORM Added here create In fact, it's also used. ORM New additions
            res.authors.add(*request.data.get("authors"))  #Manual use ORM Records of New Multi-to-Multi Third Table
            res.save()
            response["data"] = myserializers.BookSerilizers(instance=res).data  # res It's a data object that needs to be serialized to get data.data Obtain
            return Response(response)
        else:
            response["status_code"] = 101
            response['msg'] = 'New failures!'
            response["data"] = ret.errors   # If the check is unsuccessful, the error message will be automatically placed errors Li, errors = {"name":"Local error information",..."detail":"Global error message"}
            return Response(response)
        pass

    def put(self,request,**kwargs):
        response = {"status_code": 200, "msg": "Successful revision!"}
        obj = models.Book.objects.filter(id = kwargs.get("id")).first()
        ret = myserializers.BookSerilizers(instance=obj,data=request.data, many=False) # When modifying, the original data object and the information coming from the front end need to be modified. BookSerilizers Deserialization Check
        if ret.is_valid(): # When the verification is successful
            ret.validated_data['publish_id'] = request.data.get("publish_id")
            ret.validated_data['authors'] = request.data.get("authors")
            res = ret.update(instance=obj,validated_data=ret.validated_data) # Pass data objects and validated results into updates
            response["data"] = ret.validated_data
            return Response(response)
        else:
            response["data"] = ret.errors
            return Response(response)
        pass

    def delete(self,request):

        pass

 

 

Serailizer uses summary: define serialized class inherits Serailizer, define fields corresponding to model table one by one, then define local hook and global hook for verification, rewrite create and update methods, and finally instantiate serialized class in view class, and retrieve serialized data through.data

 

Let's look at the use of Model Serailizer:

Routing Layer

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^publish/$', views.PublishsView.as_view()),
    url(r'^publish/(?P<pk>\d+)/$', views.PublishView.as_view()),
    url(r'^book/$', views.BooksView.as_view()),
    url(r'^book/(?P<pk>\d+)/$', views.BookView.as_view()),
    url(r'^author/$', views.AuthorsView.as_view()),
    url(r'^author/(?P<pk>\d+)/$', views.AuthorView.as_view()),

]

 

Model Layer

from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.class Publish(models.Model):
    name = models.CharField(max_length=32)
    phone = models.CharField(max_length=15)
    address = models.CharField(max_length=255)

class Book(models.Model):
    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish = models.ForeignKey(to='Publish')
    authors = models.ManyToManyField(to='Author')

class Author(models.Model):
    name = models.CharField(max_length=32)
    sex = models.IntegerField(choices=((1,'male'),(0,'female'),(2,'secrecy')),default=1)
    info = models.CharField(max_length=255,default='This man is lazy. He didn't write anything!')

 

Serialization component layer

from rest_framework.serializers import Serializer,ModelSerializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models

"""
//Use steps:
1,New serialized class, inheritance ModelSerializer
2,The fields in the class that correspond to the model table one by one can be defined here. class Meta() Then specify the model table model And mapping fields fields,than Serializer More concise
    -The names of the classes can be changed and need to be serializers.CharField()Specified in parentheses source=A field, suggested mapping relationship
    -The field of the foreign key relationship can be used serializers.SerializerMethodField(),It needs to be fixed underneath. get_The method of field name,
        //Here you can write specific logic, and the final result is the result of the field.
3,There is no need to override the parent class when new data is added create Method, here ModelSerializer Encapsulated
4,There is no need to override the parent class when modifying the data update Method, here ModelSerializer Encapsulated
5,When these configurations are completed, calls can be instantiated in view classes, serialized, and validated when deserialized.

"""


class PublishSerializer(ModelSerializer):
    # Custom Serialized Class Inheritance ModelSerializer You can write in classes class Meta()
    class Meta():  # If you don't want each field to be written by itself, then that's fixed writing, inheritance. serializer The middle field must be written by itself, which is the difference between them.
        model = models.Publish   # Specify model tables that need to be serialized
        fields = ("__all__")   # Specify fields to be checked  "__all__" Represents all fields, or you can specify fields(Fields 1 and 2)

    def validate_name(self,value):  # Local hook  validate_To add a field name, you need to give a formal parameter, which is the field value.
        if value.startswith("sb"):
            raise ValidationError("Publishing house names contain sensitive words") # Throw an exception, but the exception is errors The information is returned to the front end and will not be reported to the back end.
        return value  # Which field needs to be returned after validation

    def validate_phone(self,value):
        if not value.isdigit():
            raise ValidationError("Publishing house contact is illegal!")
        return value

    def validate(self, attrs):  # Global hooks do global data validation. attrs That is, data that needs to be checked{"name":'xxx',...}
        name = attrs.get("name")
        phone = attrs.get("phone")
        address = attrs.get("address")
        if (not phone) and (not address):
            raise ValidationError("Publishing house contact information and address must be selected")
        return attrs

class BookSerializer(ModelSerializer):
    class Meta():
        model = models.Book
        fields = ('title','price','authors','publish')   #Specify serialized fields

#Add the following paragraph get Details of the associated fields are available when requesting data, but errors are reported when saving.  ---Convenient access, inconvenient storage, storage needs to define deserialized classes
#If you delete the following paragraph in get When requested, the associated fields will be retrieved. id Return to the front end, save without error
# =======================================================
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        res = AuthorSerializer(instance=obj.authors.all(),many=True)
        return res.data
    publish = serializers.SerializerMethodField()
    def get_publish(self,obj):
        res = PublishSerializer(instance=obj.publish)
        return res.data
# ==================================================

    def validate_title(self,value):   # Local hook check
        if value.startswith("sb"):
            raise ValidationError("The title of a book should not contain sensitive words")
        return value

    def validate_price(self,value):   # Global hook checking
        if not value:
            raise ValidationError("Book prices can't be empty!")
        try:
            float(value)
        except ValueError:
            raise ValidationError("Please enter the legal book price!")
        return value

class AuthorSerializer(ModelSerializer):
    class Meta():
        model = models.Author
        fields = ('name','sex','info')
# If the following is customized sex The value content of the field will be fetched when it is fetched. 'male','female','Other',But when you save, you will make mistakes.
# If you don't customize it, you retrieve the contents of the data store 1,0,2   Storage can pass directly through 0,1,2 Deposit, that is, the front end only needs to pass sex The digital value can be saved.
# ============================================================
    sex = serializers.CharField(source="get_sex_display")
# ============================================================

 

View Layer

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.Object_Seriailzers import PublishSerializer,BookSerializer,AuthorSerializer


# Create your views here.
#Publishing House Interface

class PublishsView(APIView):
    def get(self,request,*args,**kwargs):
        response = {"status_code":100,"msg":"query was successful!",'data':""}
        queryset = models.Publish.objects.all()
        # Serialization of multiple data needs to be developed many=True
        ret = PublishSerializer(instance=queryset,many=True)
        response['data'] = ret.data
        return Response(response)
        pass

    def post(self,request,*args,**kwargs):
        response = {"status_code":200,'msg':"New success!","data":''}
        ret = PublishSerializer(data=request.data)
        if  ret.is_valid(): # All validations, systems and customizations are performed here
            ret.save()  # Save here will execute the database save, do not need to write their own. create Method
            response['data'] = ret.data  #If it is inherited from the original Serailizer,To get filtered data, you need to pass through ret.validated_data take
        else:
            response["status_code"] = 201
            response['msg'] = 'New failures!'
            response['data'] = ret.errors
        return Response(response)

        pass

class PublishView(APIView):

    def get(self,request,pk,*args,**kwargs):
        response = {"status_code":100,'msg':'Successful query!','data':''}
        ret = PublishSerializer(models.Publish.objects.filter(pk=pk).first())
        response['data'] = ret.data # Get the serialized object
        return Response(response)
        pass

    def put(self,request,pk,*args,**kwargs):
        response = {"status_code":200,'msg':'Successful revision!','data':''}
        # Find out the object first
        query = models.Publish.objects.filter(pk=pk).first()

        # Delivery of data from database objects and front-end requests PublishSerializer serialize
        ret = PublishSerializer(instance=query,data=request.data)
        if ret.is_valid(): #Judge whether the check is passed
            # Delivery of data from database objects and front-end requests update To update, update Internally encapsulated update and save operations
            # If multiple table updates or other complex operations are involved, you can PublishSerializer Customization in update Method,update Returns the updated object
            data = ret.update(instance=query,validated_data=ret.validated_data)
            # Return the modified data and take care of it. ret.data Is filtered data, if inherited Serailizer The filtered data is ret.validated_data take
            response['data'] = ret.data
        else:
            response['status_code'] = 201
            response['msg'] = 'Modification failed!'
            response['data'] = ret.errors
        return Response(response)
        pass

    def delete(self,request,pk,*args,**kwargs):
        response = {'status_code':200,'msg':'Delete successfully!'}
        models.Publish.objects.filter(pk=pk).first().delete()
        return Response(response)
        pass

# Book interface
class BooksView(APIView):

    def get(self, request,*args,**kwargs):
        response = {"status_code":200,'msg':'Successful query!','data':''}
        queryset = models.Book.objects.all()
        ret = BookSerializer(instance=queryset,many=True)
        response['data'] = ret.data
        return Response(response)

        pass

    def post(self, request,*args,**kwargs):
        response = {"status_code": 200, 'msg': 'New success!', 'data': ''}
        ret = BookSerializer(data=request.data)
        if ret.is_valid():
            obj = ret.save()
            response['data'] = ret.data
        else:
            response['status_code'] = 201
            response['msg'] = 'New failures!'
            response['data'] = ret.errors
        return Response(response)
        pass


class BookView(APIView):

    def get(self, request,pk,*args,**kwargs):
        response = {"status_code": 200, 'msg': 'Successful query!', 'data': ''}
        ret = BookSerializer(instance=models.Book.objects.filter(pk=pk).first())
        response['data'] = ret.data
        return Response(response)
        pass

    def put(self, request,pk):
        response = {"status_code": 200, 'msg': 'Update success!', 'data': ''}
        query = models.Book.objects.filter(pk=pk).first()
        ret = BookSerializer(instance=query,data=request.data)
        if ret.is_valid():  # There if It can also be unnecessary, just need to be in the ___________ is_valid()Configuration in raise_exception=True All right.
                 # If the validation fails, the error message will be returned directly to the front end, and the following code will not go. obj
= ret.save() response['data'] = BookSerializer(instance=obj).data else: response['status_code'] = 201 response['msg'] = 'Update failed!' response['data'] = ret.errors return Response(response) pass def delete(self, request,pk): response = {"status_code": 200, 'msg': 'Delete successfully!', 'data': ''} models.Book.objects.filter(pk=pk).first().delete() return Response(response) pass # Author Interface class AuthorsView(APIView): def get(self,request): response = {"status_code": 200, 'msg': 'Successful query!', 'data': ''} queryset = models.Author.objects.all() ret = AuthorSerializer(instance=queryset,many=True) response['data'] = ret.data return Response(response) pass def post(self,request): response = {"status_code": 200, 'msg': 'New success!', 'data': ''} ret = AuthorSerializer(data=request.data) if ret.is_valid(): obj = ret.save() response['data'] = AuthorSerializer(instance=obj).data else: response['msg'] = 'New failures!' response['data'] = ret.errors return Response(response) pass class AuthorView(APIView): def get(self,request,pk,*args,**kwargs): response = {"status_code": 200, 'msg': 'Successful query!', 'data': ''} ret = AuthorSerializer(instance=models.Author.objects.filter(pk=pk).first()) response['data'] = ret.data return Response(response) pass def put(self,request,pk,*args,**kwargs): response = {"status_code": 200, 'msg': 'Update success!', 'data': ''} query = models.Author.objects.filter(pk=pk).first() ret = AuthorSerializer(instance=query, data=request.data) if ret.is_valid(): obj = ret.save() response['data'] = ret.data else: response['status_code'] = 201 response['msg'] = 'Update failed!' response['data'] = ret.errors return Response(response) pass def delete(self,request , pk, *args, **kwargs): response = {"status_code": 200, 'msg': 'Delete successfully!', 'data': ''} models.Author.objects.filter(pk=pk).first().delete() return Response(response) pass

 


Summary of Model Serailizer: On the basis of Serailizer, further encapsulation is carried out, mainly in three places:

1. Defining fields in serialized classes does not require all mapping relationships to be defined by themselves, just configuring the model table model and field fields in class Meta

2. There is no need to implement the create and update methods of the parent class in the serialized class when saving and modifying. ModelSerailizer has been encapsulated. Of course, this is only for single table operations. If multi-table operations are involved, we can also override the create and update methods ourselves.

3. After checking the data successfully, only need ret.save() to execute the create operation and ret.update to execute the update operation.

 

The pits here are:

In fact, the code also summarizes that when we use SerailizerMethodField (), we can serialize the database's associated table data by defining the method, add our own logic and get the return value, but this will cause a problem. When we use SerailizerMethodField (), the validation will filter out the data of these fields. We can add these data to validated_data to achieve our goal, but this is not the perfect solution after all. Xiaobian is ignorant of learning, and we hope Dashen will pass by and give us some advice.

Keywords: PHP Django Database JSON

Added by john_wenhold on Wed, 03 Jul 2019 22:18:22 +0300