django-rest-framework

402 阅读6分钟

参考博客

[置顶]Python系列教程 | Justin-刘清政的博客

app01/ser.py代码

from django.db import models

# Create your models here.
class Book(models.Model):
    id=models.AutoField(primary_key=True)
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    author=models.CharField(max_length=32)
    publish=models.CharField(max_length=32)
# from rest_framework.serializers import Serializer  # 就是一个类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要继承 Serializer
from app01.models import Book

def check_author(data):
    if data.startswith('sb'):
        raise ValidationError('作者名字不能以sb开头')
    else:
        return data


class BookSerializer(serializers.Serializer):
    id=serializers.CharField(read_only=True)
    name=serializers.CharField(max_length=16,min_length=4)
    # price=serializers.DecimalField()
    price=serializers.CharField(write_only=True,required=True)
    author=serializers.CharField(validators=[check_author])  # validators=[] 列表中写函数内存地址
    publish=serializers.CharField()

    def validate_price(self, data):   # validate_字段名  接收一个参数
        #如果价格小于10,就校验不通过
        # print(type(data))
        # print(data)
        if float(data)>10:
            return data
        else:
            #校验失败,抛异常
            raise ValidationError('价格太低')
    def validate(self, validate_data):   # 全局钩子
        print(validate_data)
        author=validate_data.get('author')
        publish=validate_data.get('publish')
        if author == publish:
            raise ValidationError('作者名字跟出版社一样')
        else:
            return validate_data
    def update(self, instance, validated_data):
        #instance是book这个对象
        #validated_data是校验后的数据
        instance.name=validated_data.get('name')
        instance.price=validated_data.get('price')
        instance.author=validated_data.get('author')
        instance.publish=validated_data.get('publish')
        instance.save()  #book.save()   django 的orm提供的
        return instance
    def create(self, validated_data):
        instance=Book.objects.create(**validated_data)
        return instance
        # Book.objects.create(name=validated_data.get('name'))


class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book  # 对应上models.py中的模型
        fields='__all__'
        # fields=('name','price','id','author') # 只序列化指定的字段
        # exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
        # read_only_fields=('price',)
        # write_only_fields=('id',) #弃用了,使用extra_kwargs
        extra_kwargs = {  # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
            'price': {'write_only': True},
        }

app01/views.py

from django.shortcuts import render

# Create your views here.
from django.http import JsonResponse

from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from app01.ser import BookModelSerializer
from rest_framework.response import Response  #drf 提供的响应对象

# 导入自己写的response类
from app01.utils import MyResponse
class BookView(APIView):
    def get(self,request,pk):
        book=Book.objects.filter(id=pk).first()
        #用一个类,毫无疑问,一定要实例化
        #要序列化谁,就把谁传过来
        book_ser=BookSerializer(book)  # 调用类的__init__
        # book_ser.data   序列化对象.data就是序列化后的字典
        return Response(book_ser.data)
        # return JsonResponse(book_ser.data)

    def put(self,request,pk):
        response_msg={'status':100,'msg':'成功'}
        # 找到这个对象
        book = Book.objects.filter(id=pk).first()
        # 得到一个序列化类的对象
        # boo_ser=BookSerializer(book,request.data)
        boo_ser=BookSerializer(instance=book,data=request.data)

        # 要数据验证(回想form表单的验证)
        if boo_ser.is_valid():  # 返回True表示验证通过
            boo_ser.save()  # 报错
            response_msg['data']=boo_ser.data
        else:
            response_msg['status']=101
            response_msg['msg']='数据校验失败'
            response_msg['data']=boo_ser.errors

        return Response(response_msg)

    def delete(self,request,pk):
        response=MyResponse()
        ret=Book.objects.filter(pk=pk).delete()
        return Response(response.get_dict)

class BooksView(APIView):
    # def get(self,request):
    #     response_msg = {'status': 100, 'msg': '成功'}
    #     books=Book.objects.all()
    #     book_ser=BookSerializer(books,many=True)  #序列化多条,如果序列化一条,不需要写
    #     response_msg['data']=book_ser.data
    #     return Response(response_msg)

    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book_ser=BookSerializer(books,many=True)  #序列化多条,如果序列化一条,不需要写
        response.data=book_ser.data
        return Response(response.get_dict)

    # 新增
    def post(self,request):
        response_msg = {'status': 100, 'msg': '成功'}
        #修改才有instance,新增没有instance,只有data
        book_ser = BookSerializer(data=request.data)
        # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
        # 校验字段
        if book_ser.is_valid():
            book_ser.save()
            response_msg['data']=book_ser.data
        else:
            response_msg['status']=102
            response_msg['msg']='数据校验失败'
            response_msg['data']=book_ser.errors
        return Response(response_msg)


class BooksView2(APIView):
    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book=Book.objects.all().first()
        book_ser=BookModelSerializer(books,many=True)
        book_one_ser=BookModelSerializer(book)
        print(type(book_ser))
        print(type(book_one_ser))
        response.data=book_ser.data
        return Response(response.get_dict)


APIView源码分析

drf的Request类

drf序列化

##序列化三大功能

需要在installed_app中注册一下'rest_framework',不然报错,如果使用Jsonresponse返回,则可以不用注册

序列化对象.data直接拿到json数据
可以将rest_framework的response替换成jsonresponse,前者只是给返回的数据做了一个界面美化。

序列化字段的类型

使用charfield就返回字符串格式的json

  • 数据库定义的字段类型和序列化类写的字段可以不一样,都用charfield没问题
  • 路由
  • 序列化器
  • 需要查看哪些字段就写哪些字段
  • 字段选择
  • 将从数据库取出的数据传给序列化器,再使用response转成json返回(使用drf带的response需要先把rf注册到app,否则报错模板不存在)

序列化字段选项

  • 使用接口,put,post数据时做数据校验

  • put方法修改数据

  • 之前的修改数据方式

  • 接口规范控制:抽象类abc、抛异常

  • 重写update,更新数据

  • 集成的父类中有这个父类内部调用这个方法,优先使用重写的这个方法

序列化组件修改数据

局部钩子、全局钩子校验:指定字段校验(类似form)

数据保存之前,可以使用钩子校验规则
validate_字段名     #局部钩子
validate # 全局钩子

  • readonly只可以查看,不可以写的字段
  • writeonly只可以写,不可以查
class BookSerializer(serializers.Serializer):
    id=serializers.CharField(read_only=True)
    name=serializers.CharField(max_length=16,min_length=4)
    # price=serializers.DecimalField()
    price=serializers.CharField(write_only=True,required=True)
    author=serializers.CharField(validators=[check_author])  # validators=[] 列表中写函数内存地址
    publish=serializers.CharField()
  • get
  • 序列化多条加many
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response 
class BooksView(APIView):
    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book_ser=BookSerializer(books,many=True)  #序列化多条,如果序列化一条,不需要写
        response.data=book_ser.data
        return Response(response.get_dict)
  • 新增post
  • 需要修改序列化类的create方法
ser.py
# from rest_framework.serializers import Serializer  # 就是一个类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要继承 Serializer
from app01.models import Book
class BookSerializer(serializers.Serializer):
    id=serializers.CharField(read_only=True)
    name=serializers.CharField(max_length=16,min_length=4)
    # price=serializers.DecimalField()
    price=serializers.CharField(write_only=True,required=True)
    author=serializers.CharField(validators=[check_author])  # validators=[] 列表中写函数内存地址
    publish=serializers.CharField()

    def validate_price(self, data):   # validate_字段名  接收一个参数
        #如果价格小于10,就校验不通过
        #如果价格小于10,就校验不通过
        # print(type(data))
        # print(data)
        if float(data)>10:
            return data
        else:
            #校验失败,抛异常
            raise ValidationError('价格太低')
    def validate(self, validate_data):   # 全局钩子
        print(validate_data)
        author=validate_data.get('author')
        publish=validate_data.get('publish')
        if author == publish:
            raise ValidationError('作者名字跟出版社一样')
        else:
            return validate_data
    def update(self, instance, validated_data):
        #instance是book这个对象
        #validated_data是校验后的数据
        instance.name=validated_data.get('name')
        instance.price=validated_data.get('price')
        instance.author=validated_data.get('author')
        instance.publish=validated_data.get('publish')
        instance.save()  #book.save()   django 的orm提供的
        return instance
    def create(self, validated_data):
        instance=Book.objects.create(**validated_data)
        return instance
        # Book.objects.create(name=validated_data.get('name'))


views.py
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response 
    # 新增
    def post(self,request):
        response_msg = {'status': 100, 'msg': '成功'}
        #修改才有instance,新增没有instance,只有data
        book_ser = BookSerializer(data=request.data)
        # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
        # 校验字段
        if book_ser.is_valid():
            book_ser.save()
            response_msg['data']=book_ser.data
        else:
            response_msg['status']=102
            response_msg['msg']='数据校验失败'
            response_msg['data']=book_ser.errors
        return Response(response_msg)
  • 修改put
  • 需要传book实例
  • 需要重写update方法
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response 
class BookView(APIView):
    def put(self,request,pk):
        response_msg={'status':100,'msg':'成功'}
        # 找到这个对象
        book = Book.objects.filter(id=pk).first()
        # 得到一个序列化类的对象
        # boo_ser=BookSerializer(book,request.data)
        boo_ser=BookSerializer(instance=book,data=request.data)

        # 要数据验证(回想form表单的验证)
        if boo_ser.is_valid():  # 返回True表示验证通过
            boo_ser.save()  # 报错
            response_msg['data']=boo_ser.data
        else:
            response_msg['status']=101
            response_msg['msg']='数据校验失败'
            response_msg['data']=boo_ser.errors

        return Response(response_msg)
  • delete删除
  • 直接操作book对象,不需要重写方法
from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response 
    def delete(self,request,pk):
        response=MyResponse()
        ret=Book.objects.filter(pk=pk).delete()
        return Response(response.get_dict)
  • 封装返回信息
app1/uitls.py
class MyResponse():
    def __init__(self):
        self.status=100
        self.msg='成功'
    @property
    def get_dict(self):
        return self.__dict__


if __name__ == '__main__':
    res=MyResponse()
    res.status=101
    res.msg='查询失败'
    # res.data={'name':'lqz'}
    print(res.get_dict)

  • 使用

模型类的序列化器

  • app/views.py
from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookModelSerializer
from rest_framework.response import Response  #drf 提供的响应对象
# 导入自己写的response类
from app01.utils import MyResponse
class BooksView2(APIView):
    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book=Book.objects.all().first()
        book_ser=BookModelSerializer(books,many=True)
        book_one_ser=BookModelSerializer(book)
        print(type(book_ser))
        print(type(book_one_ser))
        response.data=book_ser.data
        return Response(response.get_dict)
  • app/ser.py
  • 对应上models.py中的模型,不需重写update和create
from rest_framework import serializers
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book  # 对应上models.py中的模型
        fields='__all__'
        # fields=('name','price','id','author') # 只序列化指定的字段
        # exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
        # read_only_fields=('price',)
        # write_only_fields=('id',) #弃用了,使用extra_kwargs
        extra_kwargs = {  # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
            'price': {'write_only': True},
        }
  • 不需要重写update和create了
  • bookmodelser源码

注册app

路由分发

Django--路由控制 - 刘清政 - 博客园

Serializer高级用法

source隐藏数据库字段