I Introduction to serializer
1. Serialization and deserialization in Python
- Serialization: converting objects in Python to strings in XML format
- Deserialization: convert a string in Python format into an object in Python
2. Function of serializer
- Serialization, the serializer will convert the model object into a dictionary, and then into a json string after response
- Deserialization is to turn the data sent by the client into a dictionary after request, and the serializer can turn the dictionary into a model
- Deserialization to complete the data verification function
3. Attention
- The serialization component in drf first converts the object into dictionary format, because the dictionary format can be directly put into the Response
II Simple use of serializer
1. Use steps
-
Write a serialized class and inherit Serializer
-
Write the fields to be serialized in the class and serialize the field classes (there are many, and only a few are commonly used, which is equivalent to the field classes in models)
-
Used in the view class, import the serialization class to pass in the object to be serialized to get the serialized object
-
You can use [serialize object of class] Get serialized dictionary from data
ps: if rest is not used_ For the Response provided by the framework, you have to use JsonResponse
2. Code example
- models.py class creation
from django.db import models class Book2(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.IntegerField(max_length=8) author = models.CharField(max_length=16) publish = models.CharField(max_length=16)
- serializers.py create serializer
from rest_framework import serializers from rest_framework.serializers import ModelSerializer from drf_test import models # Define a serializer that inherits ModelSerializer class BookSerializer2(serializers.Serializer): # Write the fields you want to serialize, and write whichever sequence you want title = serializers.CharField() price = serializers.IntegerField()
- views.py writing view class
from rest_framework.viewsets import ModelViewSet from drf_test.serializers import BookSerializer2 from drf_test import models class Book2View(APIView): def get(self,request,id): # Get the object of Book from the database book_obj = models.Book2.objects.filter(nid=id).first() # Set book_obj is put into the serializer we write for serialization book_ser = BookSerializer2(book_obj) # [serialize object] data is the dictionary obtained after serialization return Response(book_ser.data)
- urls.py file
re_path('^books/(?P<id>\d+)', views.Book2View.as_view()),
- Open project test
III Field types and parameters of serialization class
1. Common field types
field | Field construction method |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) regular field, verify the regular pattern [a-zA-Z0-9 -]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format=‘hex_verbose’) format: 1) 'hex_verbose 'e.g. "5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2)' Hex 'e.g. "5ce0e9a55ffa654bcee01238041fb31a" 3)' int '- e.g. "12345678901231313134124512351145114" 4)' urn 'e.g. "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: maximum digits decimal_palces: decimal point position |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices are used in the same way as Django |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
2. Field parameters
- For CharField type
parameter | effect |
---|---|
max_length | Maximum length |
min_lenght | Minimum length |
allow_blank | Allow to be empty |
- For InterField type
parameter | effect |
---|---|
max_value | minimum value |
min_value | Maximum |
- General parameters (all fields)
parameter | effect |
---|---|
read_only | Indicates that this field is only used for serialized output. The default is False |
write_only | Indicates that this field is only used for deserialization input. The default is False |
required | Indicates that this field must be entered during deserialization. The default is True |
default | Default value to use when deserializing |
allow_null | Indicates whether the field is allowed to pass in None. The default is False |
validators | Validator used for this field |
error_messages | A dictionary containing error numbers and error messages |
label | The name of the field to be displayed when displaying API pages in HTML |
help_text | Used to display field help prompt information when HTML displays API pages |
IV Data verification and data saving of serializer
1. Data verification
-
Similar to the data verification method of the forms component learned earlier, it calls is_ Verify with the valid () method
-
First, check the field's own verification rules, then local hooks, and finally global hooks (introduced in Section 5)
-
When using serializer for deserialization, the data needs to be verified before obtaining the successfully verified data or saving it as a model class object
# Write in view class class PublishView(APIView): # New data method def post(self,request): # Pass in the json format data submitted by the front end and get the deserialized object publish_ser = serializer.PublishSerializer(data=request.data) # Use is_ The valid () method performs data verification and returns True and False if publish_ser.is_valid(): # Save manually # Get the created object res = modeels.Publish.objects.create(**publish_ser.validated_data) # Assign it to instance publish_ser.instance = res return Response(publish_ser.data) else: return Response(publish_ser.errors)
2. Data storage
- Above, we manually assign the new object to the instance of the sequencer object to save it
- In fact, we can directly use the sequencer object save() method
- But use The save() method requires you to override this method:
If the Serializer is inherited, call if the data is added or updated Both the create method and the update method need to be rewritten when the save() method saves data. If the ModelsSerializer is inherited, it does not need to be rewritten
- serializer. Rewrite method in py serializer
from rest_framework import serializers class PublishSerializer(serializers.Serializer): ... # Override the create method def create(self,valodated_data): res = models.Punlish.objects.create(**validated_data) return res # Override the update method def update(self,instance,validated_data): # Manually obtain data for assignment modification name = validated_data.get('name') city = validated_date.get('city') email = validated_data.get('email') instance.name = name instance.city = city instance.email = email instance.save() return instance
- views.py view class save()
class PublishView(APIView): ... # New data def post(self,request): publish_ser = serializer.PublishSerializer(data=request.data) if publish_ser.is_valid(): # Direct call Save publish_ser.save() return Response(publish_ser.data) else: return Response(publish_ser.errors) class PublishDetailView(APIView): ... # Modify data def put(self,request,id): publish = models.Publish.objects.filter(pk=id).first() # The object to be modified and the data passed in from the front end are passed in publish_ser = serializer.PublishSerializer(instance=publish,data=request.data) # Get the deserialized object for verification if publish_ser.is_valid(): publish_ser.save() return Response(publish_ser.data) else: return Response(publish_ser.errors)
The output error information (errors) is in English. If you want the error to be displayed in Chinese, the method is the same as that of the forms component: add error in the model class field_ The masses parameter
3. Rewrite save method of data saving
-
Another way is to rewrite the save method, but the official does not recommend rewriting this method (for understanding)
-
Override save in serialization class
class PublishSerializer(serializers.Serializer): ... # Overwrite save def save(self, **kwargs): # kwargs is the verified data # Inside the save of the parent class, create is called, so we rewrite create and pass in the data res=models.Publish.objects.create(**kwargs) return res
- Use in view classes
class PublishView(APIView): ... # New data def post(self,request): publish_ser = serializer.PublishSerializer(data=request.data) if publish_ser.is_valid(): # Manual parameter transfer is required to rewrite save res = publish_ser.save(**publish_ser.validated_data) publish_ser.instance = res return Response(publish_ser.data) else: return Response(publish_ser.errors)
4.is_ Raise of valid()_ Exception parameter
- is_ The valid () method can also throw an exception serializers when validation fails Validationerror, you can pass raise_ When the exception = true parameter is enabled, the REST framework will return an HTTP 400 error request response to the front end after receiving this exception
publish_ser.is_valid(raise_exception=True)
V Three methods of field serializer
1. Verification of fields in serializer
# When writing serialization class fields, add parameters to control the verification conditions class PublishSerializer(serializers.Serializer): nid = serializers.IntegerField(required=False) # Required name = serializers.CharField(min_length=3) # The minimum length is 3 city = serializers.CharField(max_length=16) # Up to 16 email = serializers.EmailField()
2. Use hook function (global hook, local hook)
- Local hook: validate_ [field name]
# Verification name cannot start with "xxx" def validate_name(self, data): # data is the value of the current field if data.startswith('xxx'): raise ValidationError('Can't take"xxx"start') else: return data # Return the verified value
- Global hook: validate
# The verification name cannot have the same name as the city def validate(self, attrs): name = attrs.get('name') city = attrs.get('city') if name == city: raise ValidationError('The name cannot be the same as the city name!') else: return attrs # Return all data
3. Use the field parameter validators to verify
- This parameter can specify the verification function, which is applicable to the same verification for multiple fields
- If it is troublesome to write hooks for each field, you can write a verification function, and each field uses the validators parameter to specify the function
# Define a check function def name_start(data): if data.startswith('xxx'): raise ValidationError('Can't take"xxx"start') else: return data # Then add the validators parameter to the field to be verified to specify the verification function author = serializers.CharField(validators=[name_start]) ... city = serializers.CharField(validators=[name_start]) ...
Vi read_only and write_only
1. Common field parameters
- read_only: indicates that this field is only used for serialization output. The default is False (it can only be viewed and cannot be modified)
- write_only: indicates that this field is only used for deserialization input, and the default is False (it can only be modified and cannot be viewed)
2. Code example
- urls.py
re_path('^books/(?P<id>\d+)', views.Book2View.as_view()),
- models.py
class Book2(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) price = models.IntegerField() author = models.CharField(max_length=16, null=True) publish = models.CharField(max_length=16, null=True)
- serializers.py
from rest_framework import serializers class BookSerializer2(serializers.Serializer): name = serializers.CharField(max_length=16) price = serializers.IntegerField() # read_only=True: this field is only used for serialization output. It can only be viewed and cannot be modified author = serializers.CharField(max_length=16, read_only=True) # write_only=True: this field is only used for deserialization input. It can only be modified and cannot be viewed publish = serializers.CharField(max_length=19, write_only=True) def update(self, instance, validated_data): instance.title = validated_data.get('name') instance.price = validated_data.get('price') instance.author = validated_data.get('author') instance.publish = validated_data.get('publish') instance.save() return instance
- views.py
from mydrf.serializers import BookSerializer2 from mydrf import models from rest_framework.views import APIView from rest_framework.response import Response class Book2View(APIView): def get(self, request, id): book_obj = models.Book2.objects.filter(nid=id).first() book_ser = BookSerializer2(book_obj) return Response(book_ser.data) def put(self, request, id): book_obj = models.Book2.objects.filter(nid=id).first() book_ser = BookSerializer2(instance=book_obj, data=request.data) if book_ser.is_valid(): book_ser.save() return Response(book_ser.data) else: return Response(book_ser.errors)
- query
- modify
VII Implement the interface of adding, deleting, modifying and querying
1. Demand
- Database tables: Book, Author, AuthorDatail, Publish, and establish associations between tables
- It can check all, check an item, add, modify and delete interfaces
- The name of the publishing house cannot contain the sensitive word "xxx"
2. Code implementation
- models.py
from django.db import models class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE) class AuthorDatail(models.Model): nid = models.AutoField(primary_key=True) telephone = models.BigIntegerField() birthday = models.DateField() addr = models.CharField(max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32, null=True) email = models.EmailField() def __str__(self): return self.name
- serializers.py
from mydrf import models from rest_framework import serializers from rest_framework.exceptions import ValidationError class PublishSerializer(serializers.Serializer): nid = serializers.IntegerField(required=False) name = serializers.CharField(max_length=16) city = serializers.CharField(max_length=32,error_messages={"max_length": "Too long"}) email = serializers.EmailField() # Override create def create(self, validated_data): res = models.Publish.objects.create(**validated_data) return res # Override update def update(self, instance, validated_data): instance.name = validated_data.get('name') instance.city = validated_data.get('city') instance.email = validated_data.get('email') instance.save() return instance # Local hook, check publisher name def validate_name(self, data): if "Little yellow book" in data: raise ValidationError(f'There are sensitive characters{data}') else: return data # global hook def validate(self, attrs): name = attrs.get('name') city = attrs.get('city') if name == 'Xiaohei Publishing House' and city == "Shanghai": raise ValidationError('The publishing house has been blacklisted') return attrs
- views.py
from mydrf.serializers import PublishSerializer from mydrf import models from rest_framework.views import APIView from rest_framework.response import Response class PublishView(APIView): # Get all books def get(self, request): publish_qs = models.Publish.objects.all() publish_ser = PublishSerializer(instance=publish_qs, many=True) # When there are multiple pieces of data, be sure to add them return Response(publish_ser.data) # New data def post(self, request): publish_ser = PublishSerializer(data=request.data) if publish_ser.is_valid(): publish_ser.save() return Response(publish_ser.data) else: # publish_ser.errors return Response("error") class PublishView2(APIView): # Get one def get(self, request, id): publish_obj = models.Publish.objects.filter(pk=id).first() publish_ser = PublishSerializer(instance=publish_obj) return Response(publish_ser.data) # Modify data def put(self, request, id): publish_obj = models.Publish.objects.filter(pk=id).first() publish_ser = PublishSerializer(instance=publish_obj, data=request.data) if publish_ser.is_valid(): publish_ser.save() return Response(publish_ser.data) else: return Response(publish_ser.errors) # Delete data def delete(self, request, id): # Directly delete the data and get a list of the number of items affected rows = models.Publish.objects.filter(pk=id).delete() # Take it out and judge it if rows[0] > 0: return Response('Data deleted successfully!') else: return Response('Data does not exist!')
- urls.py
path('publish/', views.PublishView.as_view()), path('publish/<int:id>', views.PublishView2.as_view()),
3. Test effect
- Check all publishers
- New publishing house
- Cannot create with sensitive words
- Blacklist cannot be created
- Check a certain item
- Modify data
- Delete data
- Delete nonexistent data
VIII source parameter
It is used to specify the fields to be serialized (fields in the data table). It is generally used in the case of one field. It can span tables, execute methods and execute
- If not specified, the default is the field name, which must correspond to the database
- If you specify source, you can rename the field
# Change field name "[Another name]" = serializers.CharField(source='publish') # Specify that the field to be serialized is publish # Cross table publish = serializers.CharField(source='publish.city') # Execute method, specify the memory address of a method defined in the model class, and it will be executed automatically in parentheses pub_date = serializers.CharField(source='times')
IX SerializerMethodField( )
It is generally used for cross table query, and a get is written inside the serializer_ [foreign key name] will display the specified data (that is, the results of multiple tables)
1. Demand
- Obtain the book information, and obtain the publisher information and all author information under the data
2. Method 1: use SerializerMethodField to implement
- serializers.py
class BookSerializer(serializers.Serializer): name = serializers.CharField() price = serializers.IntegerField() # Take out the publisher of the book publish = serializers.SerializerMethodField() def get_publish(self, obj): return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email} # Take out all the authors of the book authors = serializers.SerializerMethodField() ## for loop out all authors # def get_authors(self, obj): # li = [] # for author in obj.authors.all(): # li.append({'id':author.nid,'name':author.name,'age':author.age}) # return li # List generation writing def get_authors(self, obj): return [{'id': author.nid, 'name': author.name, 'age': author.age} for author in obj.authors.all()]
- views.py
from mydrf.serializers import BookSerializer class BookView(APIView): def get(self, request): book_qs = models.Book.objects.all() book_ser = BookSerializer(instance=book_qs, many=True) return Response(book_ser.data)
- urls.py
path('books/', views.BookView.as_view()),
- Test effect
3. Method 2: write method in model class
This method can customize the output content, such as processing some data and returning to the front end (add "*****" in the middle of the ID card)
- models.py
class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField() publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author') def __str__(self): return self.name # Take out the publisher of the book def get_publish(self): return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email} # Take out all the authors of this number def get_author(self): return [{'id': author.nid, 'name': author.name, 'age': author.age} for author in self.authors.all()]
- serializers.py
class BookSerializer(serializers.Serializer): name = serializers.CharField() price = serializers.IntegerField() # Get publishers and authors publish = serializers.DictField(source="get_publish") authors = serializers.ListField(source="get_author")
- Test effect
X Serializer class model
1.Serializer and ModelSerializer
- The Serializer serialization class we used above can not only be defined for the database model class, but also for the data of non database model classes (that is, serialize the data defined by ourselves: {"name": "shawn", "age": 18}),
- serializer is independent of the database. You need to specify the fields of the model class in the serialization class
- If we want to use the Serializer corresponding to Django's model class, DRF provides us with a ModelSerializer model class Serializer to help us quickly create a Serializer class
2. Compared with Serializer, modelserializer provides some functions
- Automatically generate a series of fields based on the model class (that is, you no longer need to define fields manually)
- Automatically generate validators for Serializer based on model class, such as unique_together
- Including the default implementation of create() and update(), you no longer need to rewrite these two methods
3. Definition of model class serializer
- Model: indicates which model class to reference
- Fields: indicates which fields are generated for the model class
class AuthorDatailSerializer(serializers.ModelSerializer): class Meta: model = models.AuthorDatail fields = '__all__'
- exclude: these fields can be excluded and cannot exist at the same time as fields
class AuthorDatailSerializer(serializers.ModelSerializer): class Meta: model = models.AuthorDatail exclude = ('phone',)
- Depth: the depth of the display. A book has the author and the author has the author information. Defining this parameter will be displayed layer by layer, and the number of layers will be controlled by yourself (understand)
- read_only_field: indicates a read-only field, which is only used to serialize the output field (deprecated, there is a better way)
- wirte_only_field: indicates that only fields are written and only used for deserializing input fields (deprecated)
class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book exclude = ('age',) depth = 3 read_only_fields = ('nid', 'price') ...
- extra_kwargs: use this parameter to add or modify the original option parameters for ModelSerializer (focus, better method)
class BookSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment') extra_kwargs = { 'price': {'min_value': 0, 'required': True}, 'publish': {'required': True, 'read_only_fields' : True}, }
4. Exercise: use an interface to add Author and AuthorDetail tables at the same time
The model table is still the model table created above, but something has been added
- models.py
class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_datail = models.OneToOneField(to='AuthorDatail', to_field='nid', unique=True, on_delete=models.CASCADE) # Get user details def get_detail(self): return {"telephone":self.author_datail.telephone,"addr":self.author_datail.addr,"birthday":self.author_datail.birthday}
- serializers.py
class AuthorSerializer(serializers.ModelSerializer): class Meta: model = models.Author fields = ['nid', 'name', 'age', 'detail', 'author_datail'] # Obtain user information data detail = serializers.DictField(source="get_detail", read_only=True) class AuthorDatailSerializer(serializers.ModelSerializer): class Meta: model = models.AuthorDatail fields = '__all__'
- views.py
from mydrf.serializers import AuthorSerializer from mydrf.serializers import AuthorDatailSerializer class AuthorView(APIView): def get(self, request): author_qs = models.Author.objects.all() author_ser = AuthorSerializer(instance=author_qs, many=True) return Response(author_ser.data) def post(self, request): # Take out the user details data author_detail = request.data.pop('detail') # Assign the remaining user data author_dict = request.data # First serialize the user details and save them author_detail_ser = AuthorDatailSerializer(data=author_detail) if author_detail_ser.is_valid(): author_detail_ser.save() # Take out the "nid" of the user detail data and add it to the "author" of the user table_ Datail "field author_detail_nid = author_detail_ser.data.get("nid") author_dict["author_datail"] = author_detail_nid # Then serialize and save the user information data author_ser = AuthorSerializer(data=author_dict) if author_ser.is_valid(): author_ser.save() return Response(author_ser.data) else: return Response(author_ser.errors) else: return Response(author_detail_ser.errors)
- urls.py
path('author/', views.AuthorView.as_view()),
- Effect demonstration
Data has been added to both tables
- Author table
- AuthorDeail table
Xi many = True source code analysis
-
Call first__ new__ method
-
If many=True, the ListSerializer object is generated
-
If many=False, the Serializer object is generated
XII Sub serialization
If you want to rewrite a field in the serializer (for example, add "xxx" suffix to the author name of Book)
1. You can use source to specify a method memory address
# models. Write methods in model classes in py files def join_xxx(self,obj): return obj.name + "xxx" # serializers.py file, and override the field specifying method in the corresponding Book serialization class authors = serializer.CharField(source='join_xxx')
2. You can use SerializerMethodField to operate
# serializers. Book serializer writing in py file authors = serializers.SerializerMethodField() def join_xxx(self,obj): return obj.name + "xxx"
3. Sub serialization can be used for operation
-
You need to create a subclass of serialization
-
The sub serialization class must be written above and can only be overridden by external key fields
-
Foreign key fields that use sub serialization cannot be deserialized
-
For sub serialization, fill in many=False for single data and many=True for multiple data
# serializers. Create a sub serialization class in py file and add the sub serialization class to the serialization class # The subclass must be written above class AuthorSerializer(serializer.ModelSerializer): class Meta: model = models.Author fields = ["name"] class BookSerializer(serializer.ModelSerializer): # Write sub serialized fields authors = AuthorSerializer(many=True, read_only=True) class Meta: model = models.Book fields = ["name","price","publish","authors"]