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.