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

     

 

 

 

posted @ 2019-01-15 19:31  一路向北_听风  阅读(190)  评论(0)    收藏  举报