这里的介绍的serializers.ModelSerializer就和我们之前学习的modelform一样
serializers.ModelSerializer如下几个功能
1、序列化queryset数据
2、反序列化json数据,将反序列化后的数据转换成model对象
3、反序列化的时候还是可以对数据做校验
4、如果合法,可以调用sava方法进行post或者put请求操作
5、如果不合法,则返回错误
下面我们进入serializers.ModelSerializer的学习
首先写一个modelserializer的类,不知道看官有没有发现,和我们之前学的modelform几乎完全一样
class bookmodelserializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__"
然后我们在get请求中,如何通过上面的类序列化queryset对象,可以看到直接之前的serializer类替换为modelserializer类就可以了
from rest_framework.views import APIView from rest_framework.response import Response class Book_cbv(APIView): def get(self,request): query_list = models.Book.objects.all() # bs = book_serializers(query_list,many=True) bs = bookmodelserializer(query_list,many=True) print(dir(serializers)) return Response(bs.data)
通过postman发送get请求,我们看下受到的信息,我们看到一对多字段和多对多字段均为所对应对象的id,我们可以定制化的显示我们需要显示的信息,但是这里暂时不做讲解,在博客的后面我们在做讲解
上面处理完了get请求,下面我们在处理一下post请求,我们通过postman发送json信息,然后通过modelserializerlizer直接保存信息,post请求处理的代码如下
如何数据有效,则保存数据,这个也和modelform非常的类型,可以说是完全一样
def post(self,request): bs = bookmodelserializer(data=request.data) if bs.is_valid(): print(bs.validated_data) bs.save() return Response(bs.data) else: return Response(bs.errors)
下面我们通过postman发送post请求,测试一下
发送完post请求,我们看下返回的结果,将我们的新增的数据返回了
至此,modelserializar的基本用法我们就讲完了
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面我们开始定制化的处理
首先,在get请求中,对于一对多和多对多的字段,我们想定制化的显示,那么我们就可以这样做
class bookmodelserializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # 一对多,关联指定的对象,然后显示指定对象的字段 book_publish = serializers.CharField(source="book_publish.id") book_auther = serializers.SerializerMethodField() def get_book_auther(self,obj): s = "" for i in obj.book_auther.all(): s = s + i.auther_name + "|" s = s.rstrip("|") return s
重点是这里,就是serializer中处理一对多和多对多的代码拿过来就可以了
下面我们通过postman发送get请求,看下前端的显示效果,看到效果,已经实现了我们的想要的结果
上面解决了定制化的处理get请求,那么post请求行不行呢?
我们直接使用postman来做一下测试
我们看到有报错,其实的modelserializer这个类的create方法无法处理这种定制的话的数据
下面的是modelserializer类的create方法
def create(self, validated_data): """ We have a bit of extra checking around this in order to provide descriptive messages when something goes wrong, but this method is essentially just: return ExampleModel.objects.create(**validated_data) If there are many to many fields present on the instance then they cannot be set until the model is instantiated, in which case the implementation is like so: example_relationship = validated_data.pop('example_relationship') instance = ExampleModel.objects.create(**validated_data) instance.example_relationship = example_relationship return instance The default implementation also does not handle nested relationships. If you want to support writable nested relationships you'll need to write an explicit `.create()` method. """ raise_errors_on_nested_writes('create', self, validated_data) ModelClass = self.Meta.model # Remove many-to-many relationships from validated_data. # They are not valid arguments to the default `.create()` method, # as they require that the instance has already been saved. info = model_meta.get_field_info(ModelClass) many_to_many = {} for field_name, relation_info in info.relations.items(): if relation_info.to_many and (field_name in validated_data): many_to_many[field_name] = validated_data.pop(field_name) try: instance = ModelClass._default_manager.create(**validated_data) except TypeError: tb = traceback.format_exc() msg = ( 'Got a `TypeError` when calling `%s.%s.create()`. ' 'This may be because you have a writable field on the ' 'serializer class that is not a valid argument to ' '`%s.%s.create()`. You may need to make the field ' 'read-only, or override the %s.create() method to handle ' 'this correctly.\nOriginal exception was:\n %s' % ( ModelClass.__name__, ModelClass._default_manager.name, ModelClass.__name__, ModelClass._default_manager.name, self.__class__.__name__, tb ) ) raise TypeError(msg) # Save many-to-many relationships after the instance is created. if many_to_many: for field_name, value in many_to_many.items(): field = getattr(instance, field_name) field.set(value) return instance
因为我们的对象是继承了modelserializer类,所以我们重写一下create方法,就可以解决这个问题,因为如果我们的类中有create方法,会优先调用我们自己的create方法,只有当我们的类中没有create方法,才会去调用父类的create方法
首先我们在自己的类中定义一个create方法,先打印参数看看
class bookmodelserializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # 一对多,关联指定的对象,然后显示指定对象的字段 def create(self, validated_data): print(validated_data) book_publish = serializers.CharField(source="book_publish.id") book_auther = serializers.SerializerMethodField() def get_book_auther(self,obj): s = "" for i in obj.book_auther.all(): s = s + i.auther_name + "|" s = s.rstrip("|") return s
create方法我们下截图出来
我们再次通过postman发送post请求,看下打印的结果
这里我无论如何怎么处理,在新的create方法中均无法打印出book_auther的数据,我也是很纳闷
无论我在上面的函数中返回一个字符串,还是一个list,都不行
上面这一行是reqeust.data中的数据,下面这一行是validated_data中的数据
那么我暂时把多对多中的定制化处理注销掉,用默认的方式显示把
class bookmodelserializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # 一对多,关联指定的对象,然后显示指定对象的字段 def create(self, validated_data): print("validated_data",validated_data) # models.Book.objects.create( # book_name = validated_data # ) book_publish = serializers.CharField(source="book_publish.id") # book_auther = serializers.SerializerMethodField() # def get_book_auther(self,obj): # # s = [] # for i in obj.book_auther.all(): # s.append(i) # # # return s
这次我们通过postman发送post请求
这次validated_data中就有book_auther信息就了
然后我们调用create方法在数据库中创建数据就可以了
class bookmodelserializer(serializers.ModelSerializer): class Meta: model = models.Book fields = "__all__" # 一对多,关联指定的对象,然后显示指定对象的字段 def create(self, validated_data): print("validated_data",validated_data) ret = models.Book.objects.create( book_name = validated_data["book_name"], book_price = validated_data["book_price"], book_publish_id = validated_data["book_publish"]["id"] ) ret.book_auther.add(*validated_data["book_auther"]) return ret
这个时候我们在通过postman发送post请求,可以看到创建数据成功了
至于定制化的多对多字段,我下来在研究一下,今天太晚了,明天还得上班!