zoukankan      html  css  js  c++  java
  • Django REST framework序列化

    一.简介

    Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API。

    官网:https://www.django-rest-framework.org/

    中文文档:https://q1mi.github.io/Django-REST-framework-documentation/

    二. 安装与配置

    1.安装

    pip install djangorestframework

    2.配置

    如果想要获取一个图形化的页面,需要将 rest_framework 注册到项目的INSTALL_APPS中。

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'bms.apps.BmsConfig',
        'rest_framework',
    ]

    三.DRF序列化

    我们写项目想返回的是json数据,使用DRF的序列化工具serializer会非常方便

    url:

        re_path('books/$',views.BooksView.as_view()),
        re_path(r'book_pk/(?P<pk>d+)$', views.BookDetailView.as_view()),

    view:

    from rest_framework.views import APIView
    from app01.serializers import BookModelSerializer
    class BooksView(APIView):
        # 不带id的查询与新增
        """使用Django REST framework 内置的序列化"""
        def get(self, request):
            '''以JSON格式返回所有的书籍信息'''
            # 1.查出所有的书籍信息
            queryset = models.Book.objects.all()
            # 2.使用serializers序列化
            ser_obj = BookModelSerializer(queryset, many=True) # 多条数据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):
        '''查询具体的书籍,编辑书籍,删除书籍'''
        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. 获取用户 发送过来的数据并且更新对象
                # partial=True 允许局部更新,比如只改变部分数据(partial 局部的)
                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去查询具体的那本书籍queryset对象;注意不是具体的书籍对象,书籍对象没有delete方法
            book_obj = models.Book.objects.filter(pk=pk)
            if book_obj:
                # 删除书籍对象
                book_obj.delete()
                return Response("删除成功")
            else:
                return Response("无效的书籍id")
    serializers.py
    class BookSerializers(serializers.Serializer):
        '''使用Serializer,序列化'''
        id = serializers.IntegerField(required=False) # required=False 设置为非必须要字段
        title = serializers.CharField(max_length=32)
        pub_date = serializers.DateField()
        CHOICES = ((1, 'Python'), (2, 'Go'), (3, 'Linux'))
        # read_only=True 设置为只在查询字段时生效
        category = serializers.CharField(source='get_category_display', read_only=True)
        # read_only=True 设置为只在添加字段,或修改字段时生效
        post_category = serializers.IntegerField(write_only=True)
    
        publisher = PublisherSerializer(read_only=True)
        post_publisher = serializers.IntegerField(write_only=True)
    
        # many= True 当字段对应多条数据时使用
        authors = AuthorSerializer(many=True, read_only=True)
        post_authors = serializers.ListField(write_only=True)
    
        def validate_title(self, attrs):
            """类似于Form组件的局部勾子函数"""
            # attrs就是需要检验的这个字段的值
            print(attrs) # 红烧牛肉
            print('-' * 120)
            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_obj = models.Book.objects.create(
                title=validated_data['title'],
                pub_date=validated_data['pub_date'],
                category=validated_data['post_category'],
                publisher_id=validated_data['post_publisher'],  # 1
            )
            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中取出数据挨个字段更新
            instance.title = validated_data.get('title', instance.title)
            instance.pub_date = validated_data.get('pub_date', instance.pub_date)
            instance.category = validated_data.get('post_category', instance.category)
            instance.publisher_id = validated_data.get('post_publisher', 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
    
    
    # 使用modelserializers
    class BookModelSerializer(serializers.ModelSerializer):
        '''使用ModelSerializer,序列化'''
        # SerializerMethodField 会自动去找 get_字段名 的方法执行(设置了SerializerMethodField)
        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):
            # book_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},
            }
  • 相关阅读:
    vue双向数据绑定原理
    vue-router原理
    CSS选择器优化
    静态资源的渲染阻塞
    什么是Base64?Base64的原理是什么?
    OAuth的解释
    AMD与CMD的区别
    AMD的实现
    组件通信的几种方式
    关于istream_iterator<int>(cin)和istream_iterator<int>()的一点分析
  • 原文地址:https://www.cnblogs.com/zwq-/p/10263888.html
Copyright © 2011-2022 走看看