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},
        }

 

posted @ 2019-01-14 08:52  清风_Z  阅读(244)  评论(0编辑  收藏  举报