day 089 DRF -- 序列化
主要内容:
- 1.示例的表结构
- 2.路由
- 3.序列化类
- 4.视图
- 5. APIView
1.表结构
class Publisher(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField() CHOICES = ((1,'Python'),(2,'Linux'),(3,'GO')) category = models.IntegerField(choices=CHOICES) publisher = models.ForeignKey(to='Publisher',on_delete=models.CASCADE) authors= models.ManyToManyField(to='Author') def __str__(self): return self.title
2.路由
#以的book为例,使用CBV url(r'books/$', views.BookListView.as_view()), url(r'book/(?P<pk>\d+)$', views.BookDetailView.as_view()),
3.序列化类
3.1 使用 Serializers
''' 专门用来做序列化的工具类 ''' from rest_framework import serializers from DRF import models class PublisherSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32) publish_date = serializers.DateField() CHOICES= ((1, 'Python'), (2, 'Linux'), (3, 'GO')) #read_only =True即正向序列化时,从数据库读取的数据进行序列化 category = serializers.CharField(source='get_category_display',read_only=True) #write_only = True 即反向序列化时从提交经过校验的数据写入数据库文件,此时提交的就是choices序号 post_category = serializers.IntegerField(write_only=True) publisher= PublisherSerializer(read_only=True) post_publisher = serializers.IntegerField(write_only=True) #同样是序列化多个对象,使用 many=True authors=AuthorSerializer(read_only=True,many=True) post_authors = serializers.ListField(write_only=True) #关于反序列化 将一个字符创序列化成一个对象可以自定义校验规则 def validate_title(self, attrs): # attrs就是需要检验的这个字段的值 """类似于Form组件的局部钩子 ,使用validate_字段名""" if '红烧牛肉' in attrs: raise serializers.ValidationError('你是魔鬼吗?') else: return attrs def validate_post_publisher(self, attrs): # 判断数据库里面有没有你制定的这个出版社 is_exist = models.Publisher.objects.filter(pk=attrs) if is_exist: return attrs else: raise serializers.ValidationError("你填写的出版社不存在!") # # 全局钩子 # def validate(self, attrs): # pass #要想直接.save保存数据必须要重写这个方法 def create(self,validated_data): ''' validated_data: 是见过校验的有效数据 根据提供的验证过的数据创建并返回一个新的'Book'实例 ''' print(validated_data) book_obj = models.Book.objects.create( title = validated_data['title'], publish_date = validated_data['publish_date'], category=validated_data['post_category'], publisher_id = validated_data['post_publisher'] ) #此处的set接收一个列表 book_obj.authors.set(validated_data['post_authors']) return book_obj #在更新数据时候支持直接调用save保存数据 def update(self,instance,validated_data): print(instance) print(validated_data) # 从 validated_data中取出数据进行更新,取不到就使用原来book_obj的数据,应为做的是局部更新 instance.title = validated_data.get('title',instance.title) instance.publish_date = validated_data.get('publish_date',instance.publish_date) instance.category = validated_data.get('category',instance.category) instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id) instance.save() #更新多对多字段 authors # 先取出当前书籍 的所有作者id author_list =instance.authors.all().values_list('id') # [(1,),(2,)] ==> [1, 2] instance.authors.set(validated_data.get('post_authors',[i[0] for i in author_list ])) return instance
3.2 使用ModelSerializer
from rest_framework import serializers from bms import models class PublisherSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class AuthorSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class BookModelSerializer(serializers.ModelSerializer): # SerializerMethodField 会自动去找 get_字段名 的方法执行 category_info = serializers.SerializerMethodField(read_only=True) publisher_info = serializers.SerializerMethodField(read_only=True) authors_info = serializers.SerializerMethodField(read_only=True) def get_category_info(self, book_obj): # obj ==》 当前被序列化的那个书籍对象 return book_obj.get_category_display() def get_publisher_info(self, book_obj): # book_obj.pulisher ==> 得到和我这本书关联的出版社对象 # return { # "id": book_obj.publiser.id, # "name": book_obj.publiser.name # } # ser_obj = PublisherSerializer(book_obj.publisher) # return ser_obj.data return PublisherSerializer(book_obj.publisher).data def get_authors_info(self, book_obj): return AuthorSerializer(book_obj.authors.all(), many=True).data class Meta: model = models.Book fields = "__all__" # depth = 1 # 所有有关系的字段都变成 read_only # exclude = [] # 排除某个字段 extra_kwargs = { # 每个字段的一些额外参数 'publisher': {'write_only': True}, 'authors': {'write_only': True}, 'category': {'write_only': True}, }
4.视图
Serializer
from DRF.serializers import BookSerializer from rest_framework.response import Response from rest_framework.views import APIView from DRF import models class BookListView(APIView): def get(self, request): """以JSON格式返回所有的书籍信息""" # 1. 查出所有的书籍信息 queryset = models.Book.objects.all() # 2. 使用serizlizer序列化 #正向序列化 ,序列化查询结果集(queryset)此时不是模型实例。我们只需要为serializer添加一个many=True标志 ser_obj = BookSerializer(queryset, many=True) return Response(ser_obj.data) def post(self, request): # 1. 获取前端提交的数据 # 1.1 APIView # self.request是谁? 不是Django原来的哪个request self._request才是原来的request print(request.data) # request.data是APIView 包装的数据 # 2. 对数据做有效性校验 #反序列化同样调用的同样是是序列化类 ser_obj = BookSerializer(data=request.data) if ser_obj.is_valid(): # 调用的是BookSerializer类中的create方法,需要自己去实现 ser_obj.save() # 3. 拿到序列化的数据去数据库创建新记录 return Response("ok") else: return Response(ser_obj.errors) class BookDetailView(APIView): """这是书籍详情相关的接口 支持:GET/PUT/DELETE""" def get(self, request, pk): """获取具体某本书的信息""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 将书籍对象 序列化成 json格式的数据 ser_obj = BookSerializer(book_obj) # 3. 返回响应 return Response(ser_obj.data) else: return Response("无效的书籍id") def put(self, request, pk): """修改具体某一本书""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 获取用户 发送过来的数据并且更新对象,即赋值给instance的book_obj对象 ,partial=True的意识允许做局部更新 ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True) # form组件中也有类似的实现 if ser_obj.is_valid(): # 3. 保存并返回修改后的数据 ser_obj.save() return Response(ser_obj.data) else: return Response(ser_obj.errors) else: return Response("无效的书籍id") def delete(self, request, pk): """删除具体某一本书""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk) if book_obj: # 删除书籍对象 book_obj.delete() return Response("删除成功") else: return Response("无效的书籍id")
ModelSerializer
rom bms.serializers import BookSerializer from rest_framework.response import Response from rest_framework.views import APIView from bms.modelserializers import BookModelSerializer class BookListView(APIView): """第四版:使用Django REST framework 内置的序列化""" def get(self, request): """以JSON格式返回所有的书籍信息""" # 1. 查出所有的书籍信息 queryset = models.Book.objects.all() # [Book_obj1, Book_obj2, ...] # 2. 使用serizlizer序列化 ser_obj = BookModelSerializer(queryset, many=True) return Response(ser_obj.data) # def post(self, request): # 1. 获取前端提交的数据 # 1.1 APIView # self.request是谁? 不是Django原来的哪个request self._request才是原来的request print(request.data) # APIView 包装的数据 # 2. 对数据做有效性校验 ser_obj = BookModelSerializer(data=request.data) if ser_obj.is_valid(): ser_obj.save() # 调用的是BookSerializer类中的create方法,需要自己去实现 # 3. 拿到序列化的数据去数据库创建新记录 return Response("ok") else: return Response(ser_obj.errors) class BookDetailView(APIView): """这是书籍详情相关的接口 支持:GET/PUT/DELETE""" def get(self, request, pk): """获取具体某本书的信息""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 将书籍对象 序列化成 json格式的数据 ser_obj = BookModelSerializer(book_obj) # 3. 返回响应 return Response(ser_obj.data) else: return Response("无效的书籍id") def put(self, request, pk): """修改具体某一本书""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk).first() if book_obj: # 2. 获取用户 发送过来的数据并且更新对象 ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True) # form组件中也有类似的实现 if ser_obj.is_valid(): # 3. 保存并返回修改后的数据 ser_obj.save() return Response(ser_obj.data) else: return Response(ser_obj.errors) else: return Response("无效的书籍id") def delete(self, request, pk): """删除具体某一本书""" # 1. 根据pk去查询具体的那本书籍对象 book_obj = models.Book.objects.filter(pk=pk) if book_obj: # 删除书籍对象 book_obj.delete() return Response("删除成功") else: return Response("无效的书籍id")
5. APIView
- 5.1 在APIview中,dispatch方法中的 request
def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs)
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context ) #返回一个Request类的实例对象
- 5.2 Request 类中的属性方法
# 此时通过 request.query_params可以得到原来Url里的参数 @property def query_params(self): """ More semantically correct name for request.GET. """ return self._request.GET #新的request.data能够得到post提交过来的所有数据 @property def data(self): if not _hasattr(self, '_full_data'): self._load_data_and_files() return self._full_data