current position:Home>Django serialization (II)
Django serialization (II)
2022-01-31 15:31:03 【Waiting for】
This is my participation 11 The fourth of the yuegengwen challenge 13 God , Check out the activity details :2021 One last more challenge
One 、 Source analysis
1. Basic knowledge of classes
Class is executed before instantiation __new__ Method , Used to control the process of generating instances of a class
Subclasses don't have __new__ Method executes the of the parent class __new__ Method
__new__ After the method is executed, execute __init__ Construction method
2. With ModelSerializer For example , nothing __new__ Method , Its parent class Serializer either , Upper parent class BaseSerializer contains __new__ Method , For analysis, see the notes , The following is the source code :
class BaseSerializer(Field):
""" The BaseSerializer class provides a minimal class which may be used for writing custom serializer implementations. Note that we strongly restrict the ordering of operations/properties that may be used on the serializer in order to enforce correct usage. In particular, if a `data=` argument is passed then: .is_valid() - Available. .initial_data - Available. .validated_data - Only available after calling `is_valid()` .errors - Only available after calling `is_valid()` .data - Only available after calling `is_valid()` If a `data=` argument is not passed then: .is_valid() - Not available. .initial_data - Not available. .validated_data - Not available. .errors - Not available. .data - Available. """
def __init__(self, instance=None, data=empty, **kwargs): # many=False Construction method executed after
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super(BaseSerializer, self).__init__(**kwargs)
def __new__(cls, *args, **kwargs):
# We override this method in order to automagically create
# `ListSerializer` classes instead when `many=True` is set.
if kwargs.pop('many', False): # many Parameters , If so, execute cls.many_init, If not, execute super(BaseSerializer).__new__
return cls.many_init(*args, **kwargs) # many=True, Said to QuerySet To deal with , Take this logic ,
return super(BaseSerializer, cls).__new__(cls, *args, **kwargs) # many = False , Represents processing of individual objects
Copy code
Perform play __new__ Method then executes __init__ Construction method , At this time, there is a basis many Different values perform different construction methods , When many=True Time to execute cls.many_init Method ,
@classmethod
def many_init(cls, *args, **kwargs): # many=True, Execute the method
""" This method implements the creation of a `ListSerializer` parent class when `many=True` is used. You can customize it if you need to control which keyword arguments are passed to the parent, and which are passed to the child. Note that we're over-cautious in passing most arguments to both parent and child classes in order to try to cover the general case. If you're overriding this method you'll probably want something much simpler, eg: @classmethod def many_init(cls, *args, **kwargs): kwargs['child'] = cls() return CustomListSerializer(*args, **kwargs) """
allow_empty = kwargs.pop('allow_empty', None)
child_serializer = cls(*args, **kwargs)
list_kwargs = {
'child': child_serializer,
}
if allow_empty is not None:
list_kwargs['allow_empty'] = allow_empty
list_kwargs.update({
key: value for key, value in kwargs.items()
if key in LIST_SERIALIZER_KWARGS
})
meta = getattr(cls, 'Meta', None)
list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
return list_serializer_class(*args, **list_kwargs) # Finally using ListSerializer instantiate
Copy code
From the above source code, we know , For individual objects , It's using Serializer Class for processing , If the object is QuerySet type ( Multiple object lists ), use LIstSeriallizer Handle , At this point, we call the... Of the object data Property to get the result ( In the example, this uses res.data), Here is the source code ( When searching, first look for the subclass , Without this attribute, go to the parent class to find ):
@property
def data(self):
ret = super(Serializer, self).data # Execute parent data attribute
return ReturnDict(ret, serializer=self)
Copy code
Parent class BaseSerialize Property method of data Source code :
@property
def data(self):
if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'): # For data validation, use
msg = (
'When a serializer is passed a `data` keyword argument you '
'must call `.is_valid()` before attempting to access the '
'serialized `.data` representation.\n'
'You should either call `.is_valid()` first, '
'or access `.initial_data` instead.'
)
raise AssertionError(msg)
if not hasattr(self, '_data'):
if self.instance is not None and not getattr(self, '_errors', None):# Judge whether there is a mistake , Serialization without error
self._data = self.to_representation(self.instance) # take instance(QuerySet object ) Pass in , Start serializing
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
self._data = self.to_representation(self.validated_data)
else: self._data = self.get_initial()
return self._data
Copy code
From the above source code, we can see , The serialization method is implemented by calling the class self.to_representation Method to serialize , So let's see Serializer Class to_representation Method
def to_representation(self, instance):
""" Object instance -> Dict of primitive datatypes. """
ret = OrderedDict() # First the instance Into an ordered Dictionary
fields = self._readable_fields
for field in fields: # Loop defined fields , This field can be defined by ourselves , It can also be model In the field
try:
attribute = field.get_attribute(instance) # Calling field get_attribute Method ( Parameters are objects ), In the example, it can be understood as group.get_attribute(group_obj),
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
Copy code
In the above source code , call field.get_attribute(instance) Method to get the data of each field , Here is field.get_attribute(instance) Source code ( stay Field in )
def get_attribute(self, instance):
""" Given the *outgoing* object instance, return the primitive value that should be used for this field. """
try:
return get_attribute(instance, self.source_attrs) # perform get_attribute function , Used to define field properties according to , Get different data , Note that this method does not bring self, It's a function , Not class methods . self.source_attrs: With '.' Split list , Will be used to get properties for reflection
except (KeyError, AttributeError) as exc:
if self.default is not empty:
return self.get_default()
if self.allow_null:
return None
if not self.required:
raise SkipField()
msg = (
'Got {exc_type} when attempting to get a value for field '
'`{field}` on serializer `{serializer}`.\nThe serializer '
'field might be named incorrectly and not match '
'any attribute or key on the `{instance}` instance.\n'
'Original exception text was: {exc}.'.format(
exc_type=type(exc).__name__,
field=self.field_name,
serializer=self.parent.__class__.__name__,
instance=instance.__class__.__name__,
exc=exc
)
)
raise type(exc)(msg)
Copy code
call get_attribute function , Further out , Need to analyze self.source_attrs Parameters , Here is self.source_attrs Part of the source code :
if self.source == '*':
self.source_attrs = []
else:
self.source_attrs = self.source.split('.')
#self.source It's our custom field source Parameters , Such as :gp=serializers.CharField(source='group.name'),sss=serializers.CharField(source='get_user_type_display') Finally, the segmentation becomes ['group','name']
Copy code
The above analysis self.source_attrs It's a list ( from source Parameters are divided by points ), Continue to back get_attribute function , Here is the source :
def get_attribute(instance, attrs):
""" Similar to Python's built in `getattr(instance, attr)`, but takes a list of nested attributes, instead of a single attribute. Also accepts either attribute lookup on objects or dictionary lookups. """
# attrs:['group','name'] perhaps ['get_user_type_display',]for attr in attrs:
# Loop list
try:
if isinstance(instance, collections.Mapping): # If it is model Field mapping (DRF Internal field conversion ), Call directly model Class
instance = instance[attr]# Reassign , At this time instance Has been changed
else:
instance = getattr(instance, attr) # otherwise , Use reflection to get results , Such as instance=getattr(userinfo_obj,group)
except ObjectDoesNotExist:
return None
if is_simple_callable(instance): # Determine whether it is executable , At this point, as in our example get_user_type_display, The judgment process is similar to the following TIPS in , I won't go into too much detail here
try:
instance = instance() # Reassign , Execute with parentheses
except (AttributeError, KeyError) as exc:
# If we raised an Attribute or KeyError here it'd get treated# as an omitted field in `Field.get_attribute()`. Instead we# raise a ValueError to ensure the exception is not masked.raise ValueError('Exception raised in callable attribute "{0}"; original exception was: {1}'.format(attr, exc))
return instance
Copy code
TIPS: Determine whether it is an executable method
import types
def func(arg):
if isinstance(arg,types.FunctionType,):
print('yes')
arg()
else:
print('NO')
func(lambda :1)
func(111)
# Execution results :
yes
NO
Copy code
From the above source code analysis , The essence of serialization is to use django Of orm Of QuerSet Or individually model Object properties , Serialization using reflection or methods .
Two 、 data validation
1. Basic verification
DRF Data verification function and django Of form It's kind of similar , Example : The global configuration is used to obtain data json Parser , It has been introduced in the parser :
class CheckGroupData(serializers.Serializer):
id=serializers.IntegerField(error_messages={'required':'id Can't be empty '})
name=serializers.CharField(error_messages={'required':' Group name cannot be empty '})
class GroupView(APIView):
def get(self,request,*args,**kwargs):
group_id=kwargs.get('xxx')
group_obj=models.UserGroup.objects.get(id=group_id)
res=UserGroupSerializer(instance=group_obj,many=False) #instance Accept queryset Object or single model object , When there are multiple pieces of data , Use many=True, Single object many=False
return HttpResponse(json.dumps(res.data,ensure_ascii=False))
def post(self,request,*args,**kwargs):
ret=CheckGroupData(data=request.data)# Global configuration is configured here json Parser , Use request.data Get data directly
if ret.is_valid():
print(ret.validated_data)
# Get a field data ret.validated_data.get('name')
return HttpResponse(' Data validation succeeded ')
else:
print(ret.errors)
return HttpResponse(' Data validation failed ')
Copy code
Use postman towards http://127.0.0.1:8000/api/v1/group/1 , send out json data , give the result as follows : Background results :
Verify that the process is effective .
2. Custom validation
and django form Function as ,DRF Serialization supports custom data validation , Example :
# Custom validation rules
class MyValidation(object):
def __init__(self,base):
self.base = base
def __call__(self, value): #value Is the field value , Default delivery
if value == 'wd':
message = " keyword %s It can't be %s"%(self.base,value)
raise serializers.ValidationError(message)
class MySerializer(serializers.Serializer):
name = serializers.CharField(validators=[MyValidation(base='name_field'),])
class GroupView(APIView):
def get(self,request,*args,**kwargs):
group_id=kwargs.get('xxx')
group_obj=models.UserGroup.objects.get(id=group_id)
res=UserGroupSerializer(instance=group_obj,many=False) #instance Accept queryset Object or single model object , When there are multiple pieces of data , Use many=True, Single object many=False
return HttpResponse(json.dumps(res.data,ensure_ascii=False))
def post(self,request,*args,**kwargs):
ret=MySerializer(data=request.data)# Global configuration is configured here json Parser , Use request.data Get data directly
if ret.is_valid():
print(ret.validated_data)
# Get a field data ret.validated_data.get('name')
return HttpResponse(' Data validation succeeded ')
else:
print(ret.errors)
return HttpResponse(' Data validation failed ')
Copy code
send out {"name":"wd"} The results of data validation are as follows :
3. Hook function
For custom validation ,DRF and django Of form Components also give us built-in hook functions , Used to verify .
Validation process : is_valid-->self.run_validation-->to_internal_value-->to_internal_value-->validate_ Field name ( Perform field validation , Hook method )-->validate_method( Hook verification method )
validate_ Field name hook method validation example :
class MySerializer(serializers.Serializer):
name = serializers.CharField()
def validate_name(self,value): # Verified field values
if value.startswith("w"):
raise serializers.ValidationError('name The field cannot be in w start ')
else:
return value # Note that it has passed the verification , Must return its value
class GroupView(APIView):
def get(self,request,*args,**kwargs):
group_id=kwargs.get('xxx')
group_obj=models.UserGroup.objects.get(id=group_id)
res=UserGroupSerializer(instance=group_obj,many=False) #instance Accept queryset Object or single model object , When there are multiple pieces of data , Use many=True, Single object many=False
return HttpResponse(json.dumps(res.data,ensure_ascii=False))
def post(self,request,*args,**kwargs):
ret=MySerializer(data=request.data)# Global configuration is configured here json Parser , Use request.data Get data directly
if ret.is_valid():
print(ret.validated_data)
# Get a field data ret.validated_data.get('name')
return HttpResponse(' Data validation succeeded ')
else:
print(ret.errors)
return HttpResponse(' Data validation failed ')
Copy code
Also send json data {"name":"wd"} To verify , give the result as follows :
copyright notice
author[Waiting for],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/01/202201311531002409.html
The sidebar is recommended
- Django (make an epidemic data report)
- Daily python, Part 8 - if statement
- Django model class 1
- The same Python code draws many different cherry trees. Which one do you like?
- Python code reading (Chapter 54): Fibonacci sequence
- Django model class 2
- Python crawler Basics
- Mapping 3D model surface distances using Python VTK
- How to implement encrypted message signature and verification in Python -- HMAC
- leetcode 1945. Sum of Digits of String After Convert(python)
guess what you like
-
leetcode 2062. Count Vowel Substrings of a String(python)
-
Analysis of Matplotlib module of Python visualization
-
Django permission management
-
Python integrated programming -- visual hot search list and new epidemic situation map
-
[Python data collection] scripy realizes picture download
-
Python interface automation test framework (basic part) -- loop statement of process control for & while
-
Daily python, Chapter 9, while loop
-
Van * Python | save the crawled data with docx and PDF
-
Five life saving Python tips
-
Django frequency control
Random recommended
- Python - convert Matplotlib image to numpy Array or PIL Image
- Python and Java crawl personal blog information and export it to excel
- Using class decorators in Python
- Untested Python code is not far from crashing
- Python efficient derivation (8)
- Python requests Library
- leetcode 2047. Number of Valid Words in a Sentence(python)
- leetcode 2027. Minimum Moves to Convert String(python)
- How IOS developers learn Python Programming 5 - data types 2
- leetcode 1971. Find if Path Exists in Graph(python)
- leetcode 1984. Minimum Difference Between Highest and Lowest of K Scores(python)
- Python interface automation test framework (basic) -- basic syntax
- Detailed explanation of Python derivation
- Python reptile lesson 2-9 Chinese monster database. It is found that there is a classification of color (he) desire (Xie) monsters during operation
- A brief note on the method of creating Python virtual environment in Intranet Environment
- [worth collecting] for Python beginners, sort out the common errors of beginners + Python Mini applet! (code attached)
- [Python souvenir book] two people in one room have three meals and four seasons: 'how many years is it only XX years away from a hundred years of good marriage' ~?? Just come in and have a look.
- The unknown side of Python functions
- Python based interface automation test project, complete actual project, with source code sharing
- A python artifact handles automatic chart color matching
- Python crawls the map of Gaode and the weather conditions of each city
- leetcode 1275. Find Winner on a Tic Tac Toe Game(python)
- leetcode 2016. Maximum Difference Between Increasing Elements(python)
- Run through Python date and time processing (Part 2)
- Application of urllib package in Python
- Django API Version (II)
- Python utility module playsound
- Database addition, deletion, modification and query of Python Sqlalchemy basic operation
- Tiobe November programming language ranking: Python surpasses C language to become the first! PHP is about to fall out of the top ten?
- Learn how to use opencv and python to realize face recognition!
- Using OpenCV and python to identify credit card numbers
- Principle of Python Apriori algorithm (11)
- Python AI steals your voice in 5 seconds
- A glance at Python's file processing (Part 1)
- Python cloud cat
- Python crawler actual combat, pyecharts module, python data analysis tells you which goods are popular on free fish~
- Using pandas to implement SQL group_ concat
- How IOS developers learn Python Programming 8 - set type 3
- windows10+apache2. 4 + Django deployment
- Django parser