这里的介绍的serializers.ModelSerializer就和咱们以前学习的modelform同样前端
serializers.ModelSerializer以下几个功能python
一、序列化queryset数据数据库
二、反序列化json数据,将反序列化后的数据转换成model对象json
三、反序列化的时候仍是能够对数据作校验app
四、若是合法,能够调用sava方法进行post或者put请求操做ide
五、若是不合法,则返回错误函数
下面咱们进入serializers.ModelSerializer的学习post
首先写一个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请求,能够看到建立数据成功了
至于定制化的多对多字段,我下来在研究一下,今天太晚了,明天还得上班!