django rest framework 学习笔记

 注意:该文章摘抄之百度,仅当做学习笔记供小白使用,若侵权请联系删除!


RESTful API 规范

REST( Representational State Transfer ) : 表征性状态转移

数据的安全保障:url 链接一般采用https协议传输,可以提高数据交互过程中的安全性

[http和https的区别是:http是未加密的明文传输的,https是ssl加密建立的安全通道]

接口特征表现:https://xxx/api 特征字段api表示是url链接时完成前后端数据交互的

多版本版本共存:xxx/v1  xxx/v2 表示同资源多版本的情况

数据同资源使用名称: xxx/user  xxx/shop 特殊接口可使用动词  xxx/login

资源操作的请求方式,常用的增删改查

  • xxx/get   获取
  • xxx/post  新增
  • xxx/put   整体修改
  • xxx/patch 局部修改
  • xxx/delete  删除

过滤-限制搜索条件

  • xxx?limit=10
  • xxx?offset=10
  • xxx?page=1&page_count=10
  • xxx?sortby=name&order=asc
  • xxx?id=1

响应状态码:

  • 200  常规请求
  • 201  创建成功
  • 301  永久重定向
  • 302  暂时重定向
  • 403  请求无权限
  • 404  请求路径失败
  • 405  请求方法不存在
  • 500  服务器异常

不同操作的规范方式:

  • get /collection   返回资源列表
  • get /collection/resource  返回单个资源对象
  • post /collection  返回新生成的资源对象
  • put /collection/resource  返回完整的资源对象
  • patch /collection/resource  返回完整的资源对象
  • delete /collection/resource  返回一个空文档

简述 django rest framework框架的认证流程

当用户进行登录的时候,运行了登录类的as_view()方法,进入了APIView类的dispatch方法 执行self.initialize_request这个方法,里面封装了request和认证对象列表等其他参数

执行self.initial方法中的self.perform_authentication,里面运行了user方法

再执行了user方法里面的self._authenticate()方法

 DRF定义

Django Rest Framework 框架是一个用于构建Web API的强大而又灵活的工具

特点:

提供了定义序列化serializer的方法,可根据ORM或其他库自动序列化/反序列化

提供丰富的类视图、Mixin扩展类,简化视图的编写

多种身份认证和权限认证方式的支持

直观的API Web界面

常见序列化器类字段类型与选项

  • BooleanField
  • CharField
  • EmailField
  • RegexField
  • URLField
  • IPAddressField
  • IntegerFileld
  • DecimalField
  • DateTimeField
  • DateField
  • TimeField
  • ChoiceField
  • MultipleChoiceField
  • FileField
  • ImageField
  • ListField
  • DictField

选项参数:

  1. max_length
  2. min_length
  3. allow_blank
  4. trim_whitespace # 是否截断空白字符
  5. max_value
  6. min_value

通用参数:

  1. read_only
  2. write_only
  3. required
  4. default
  5. allow_null
  6. validators   # 该字段使用的验证器
  7. error_messages
  8. label  #显示的字段名称
  9. help_text  # 帮助信息

 序列化过程:特征是将python 转化为 json格式数据

语法:serializer(instance=None,data={empty},**kwarg)  

运用:instance参数 序列化时使用,data参数反序列时使用 

# 响应的Python对象转化为响应报文的json字节流
eg:
student= Student.object.all()
serializer= StudentSerializer(student)    # 序列化对象
JSONRenderer().render(serializer.data())  # 字典转json字节流

# JSONRenderer()封装了json.dumps() 转化

关联字段外键的其序列化的定义方式

  1. 方法1:   PrimaryKeyRelatedField 返回关联字段的id
    user = serializers.PrimaryKeyRelatedField()
  2. 方法2: StringRelatedField 返回关联字段模型类__str__方法的内容

           user = serializers.StringRelatedField()

     3. 方法3:UserInfoSerializer 返回关联对象序列化的所有字段

           user = UserInfoSerializer()

     4. 方法4: SlugRelatedField 返回关联对象的某个特定具体字段

     user = serializers.SlugRelatedField(read_only=True,slug_field='name')

反序列化过程:

[语法:is_valid 方法用于验证是否PASS, validated_data属性获取数据,errors打印错误信息]

# 请求body的json字节流转化为Python对象
eg 保存数据:
data=JSONParser().parse(BytesIO(content))  # json字节流转化为字典
serializer= StudentSerializer(data=data)   # 反序列化将字典转为对象
serializer.is_valid()                      # 检验对象数据,成功True,否则False
serializer.save()

# 注: save() 1. 保存时调用create方法 2.更新时调用update()方法 未定义时调用会报错

eg 修改数据:
user = UserInfo.objects.get(id=1)
data = {'name':'pass','pwd':'xxx'}
ser  = UserInfoSerializer(instance=user,data=data)
if ser.is_valid():
    ser.save()

模型序列化与反序列化

模型序列化器[ serializers.ModelSerializer]: 快速创建Serializer类,其提供了

1.自动生成一系列字段

2.自动生成validators,如unique_together

3. 包含默认的create、update()的实现

class Addr(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = "__all__"

fields字段定义:

  • 可以指定具体字段 fields = ('id','age')
  • exclude 排除字段
  • read_only_fields 指定只读字段

修改字段的参数选项:extra_kwargs 可添加或修改原有的选项参数以指定对应的值效验字段规则

class Addr(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = "__all__"
        extra_kwargs ={'pwd':{'min_value':0,'required':True}}
# 原模型
class Student(models.Model):
    student_id = models.AutoField(primary_key=True, verbose_name="学生编号")
    student_name = models.CharField(max_length=8, verbose_name="学生姓名")
    student_gender = models.BooleanField(
        choices=([0, "male"], [1, "female"]), default=0, verbose_name="学生性别")
    student_class = models.ForeignKey(
        to="Classes", verbose_name="所属班级", on_delete=models.CASCADE)  # 一个班级多个学生

    def __str__(self):
        return self.student_name

    class Meta:
        db_table = ''
        managed = True
        verbose_name = 'Student'
        verbose_name_plural = 'Students'

# 序列化
from .models import Student
from rest_framework import serializers


class StudentSerializer(serializers.Serializer):
    student_id = serializers.CharField()
    student_name = serializers.CharField()
    student_gender = serializers.BooleanField()
    student_class = serializers.PrimaryKeyRelatedField(many=False, queryset=Teacher.objects.all())

    def to_representation(self, instance):
        class = instance.student_class
        ret = super(StudentSerializer, self).to_representation(instance)
        ret["student_class"] = {
            "id": class.id,
            "name": class.name
        }
        return ret

# 反序列化
from .models import Student
from rest_framework import serializers


class StudentSerializer(serializers.Serializer):
    GENDER_CHOICES = (
        (0, 'female'),
        (1, 'male')
    )
    student_id = serializers.CharField(read_only=True)
    student_name = serializers.CharField(required=True, max_length=15, label="学生姓名", help_text="学生姓名")
    student_gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
    student_class = serializers.PrimaryKeyRelatedField(many=False, queryset=Idc.objects.all())

    

swagger在线接口文档

Django REST Swagger 项目已经不维护了,并且不支持最新的Django,

所以可以选择 drf-yasg 项目作为接口文档生成器。

yasg 的功能非常强大,可以同时支持多种文档格式。

'drf_yasg', # 配置drf-yasg (API文档生成器)  # 注册app
drf_yasg API文档生成器支持两种模式,互动模式和文档模式,分别配置其对应的路由swagger/和redoc/,并通过with_ui方法去配置这两种模式。
在浏览器中输入url/swagger/,进入互动模式
在浏览器中输入url/redoc/,进入文档模式

修饰视图装饰器api_view

app目录下的views.py文件,添加以下代码。比如这个接口,单纯就是返回一些信息,不想让用户访问,但是又不想让用户知道他没权限访问。
这个接口并没有与数据库有数据交互,只是用了视图装饰器 api_view 处理请求和响应

@api_view('GET')
def testing_api(request):
    return Response(data={"retcode":status.HTTP_200_OK,'msg':'loading...'})

这里可以采用swagger_auto_schema装饰器修饰视图函数,operation_summary参数指 接口摘要信息、operation_description指 接口描述信息
views.py
# 导入swagger_auto_schema装饰器
from drf_yasg.utils import swagger_auto_schema

@swagger_auto_schema(method='GET',operation_summary='定制化API', operation_description='loading...')
@api_view('GET')
def testing_api(request):
    return Response(data={"retcode":status.HTTP_200_OK,'msg':'loading...'})

# url.py
urlpatterns = [
    path('',include(router.urls)),
    path('swagger/',schema_view.with_ui('swagger',cache_timeout=0),name='schema-swagger-ui'),   #互动模式
    path('redoc/',schema_view.with_ui('redoc',cache_timeout=0),name='schema-redoc'),   #文档模式
    path('testing/',sqtp_view.testing_api),
]

修饰视图集 如果视图采用类或者视图集,视图函数本身是继承父类,没有出现在编写的代码中该如何自定义接口描述呢?

# 导入django装饰器
from django.utils.decorators import method_decorator

@method_decorator(name='list',decorator=swagger_auto_schema(operation_summary='查询数据', operation_description='查询所有教师数据'))
@method_decorator(name='create',decorator=swagger_auto_schema(operation_summary='新增数据', operation_description='新增教师信息数据'))
@method_decorator(name='destroy',decorator=swagger_auto_schema(operation_summary='删除数据', operation_description='删除指定教师信息数据'))
class RequestViewSet(viewsets.ModelViewSet):
    queryset = Request.objects.all()  # 数据的查询集
    serializer_class = RequestSerializer
这里参数 name,list指查询所有数据;create指新增数据;update指修改数据;destroy指删除数据;retrieve指查询单条数据;

rest_framework_simplejwt自定义使用——登录功能

# url.py
from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView, TokenObtainPairView
urlpatterns = [
    path("login/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
    path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
    path("verify/", TokenVerifyView.as_view(), name="token_verify"),
]
# 这三个接口分别是登录、获取新的token、验证token是否有效
#  TokenObtainPairView.as_view(),这个接口登录成功后会返回:访问令牌和有效令牌。
Django模型元数据Meta选项详解      
class Meta:
            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "table_name"
          
            # 联合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)
            
            # admin中显示的表名称
            verbose_name
            
            # verbose_name加s
            verbose_name_plural
   
rolekey = serializers.SerializerMethodField(read_only=True)  # 新增自定义字段

前四个只支持CharField字段,后两个只支持IntegerField字段
通用参数
参数名称    说明
read_only    表明该字段仅用于序列化输出,默认False
write_only    表明该字段仅用于反序列化输入,不用做序列化的输出,也就是只用于数据校验,默认False
required    表明该字段在反序列化时必须输入,默认True
default    反序列化时使用的默认值
allow_null    表明该字段是否允许传入None,默认False
validators    该字段使用的验证器
error_messages    包含错误编号与错误信息的字典
label    用于HTML展示API页面时,显示的字段名称
help_text    用于HTML展示API页面时,显示的字段帮助提示信息
我们的字段默认都是既序列化又需反序列化的。

read_only=True,序列化时序列化出该字段数据,反序列化校验时不校验这个数据

write_only=True,序列化时不序列化这个字段数据,反序列校验时,需要客户端传递这个数据过来进⾏校验
也可以在Meta元类中通过extra_kwargs直接为隐式字段传入额外参数error_messages

class Meta:
    model = User
    fields = ['id', 'username', 'password', 'mobile', 'passwordConfirm', 'smsCode']
    # 给隐式字段 添加/修改属性
    extra_kwargs = {
        'username': {
            'min_length': 5,
            'max_length': 20,
            'error_messages': {
                'min_length': '仅允许5-20个字符的用户名',
                'max_length': '仅允许5-20个字符的用户名',
            }
        },
        'password': {
            'write_only': True,
            'min_length': 8,
            'max_length': 20,
            'error_messages': {
                'min_length': '仅允许8-20个字符的密码',
                'max_length': '仅允许8-20个字符的密码',
            }
        }
    }

文件传输

HttpResponse、StreamingHttpResponse和FileResponse区别和选择

Django 提供三种方式实现文件下载功能,分别是:HttpResponse、StreamingHttpResponse和FileResponse

    HttpResponse 是所有响应的核心类,它的底层功能类是HttpResponseBase。
    StreamingHttpResponse 是在HttpResponseBase 的基础上进行继承与重写的,它实现流式响应输出(流式响应输出是使用Python的迭代器将数据进行分段处理并传输的),适用于大规模数据响应和文件传输响应。
    FileResponse 是在StreamingHttpResponse 的基础上进行继承与重写的,它实现文件的流式响应输出,只适用于文件传输响应。

HttpResponse 实现文件下载存在很大弊端,其工作原理是将文件读取并载入内存,然后输出到浏览器上实现下载功能。如果文件较大,该方法就会占用很多内存。对于下载大文件,Django推荐使用StreamingHttpResponse 和FileResponse 方法,这两个方法将下载文件分批写入服务器的本地磁盘,减少对内存的消耗。

StreamingHttpResponse和FileResponse对象的对比和选择

StreamingHttpResponse对象需要一个生成器函数来按需生成要发送的数据块。FileResponse对象支持直接读取文件并以块的形式生成响应数据。

由于FileResponse对象使用Python内置的文件迭代器进行分块传输,因此它对文件大小有一定的限制(默认情况下为django.http.response.FILE_CHUNK_SIZE配置)。如果您需要传输超过该限制的文件,则需要使用StreamingHttpResponse对象进行流式传输。

HttpResponse

设置content_type和Content-Disposition头文件以指示浏览器将文件作为附件下载。

使用HttpResponse对象读取整个文件并将其存储为内存中的字符串,这意味着对于大型文件可能会消耗大量的内存资源。

总结:下载大文件时,该方法不太适用!

import os
from django.http import HttpResponse

def download_file(request):
    file_path = '/path/to/my/file.txt'
    if os.path.exists(file_path):
        with open(file_path, 'rb') as f:
            file_data = f.read()
        response = HttpResponse(file_data, content_type='application/octet-stream')
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
        return response
    else:
        return HttpResponse("Sorry, the file you requested does not exist.")

StreamingHttpResponse

使用StreamingHttpResponse对象可以解决使用HttpResponse下载大型文件时内存消耗过高的问题。与HttpResponse不同,StreamingHttpResponse不会一次性将整个文件加载到内存中,而是将数据流式传输到客户端

总结,生成器函数是一种能够在需要时逐步生成数据的Python函数。当您需要处理大型文件或数据时,生成器函数非常有用,因为它们可以在需要时按块生成数据,并且可以避免一次性加载大量数据到内存中。

import os
from django.http import StreamingHttpResponse

def download_file(request):
    file_path = '/path/to/my/file.txt'
    if os.path.exists(file_path):
        def file_iterator(file_path, chunk_size=8192):
            with open(file_path, 'rb') as f:
                while True:
                    chunk = f.read(chunk_size)
                    if not chunk:
                        break
                    yield chunk

            response = StreamingHttpResponse(file_iterator(file_path))
            response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))

            return response
    else:
        return HttpResponse("Sorry, the file you requested does not exist.")

使用FileResponse对象可以有效地传输大型文件,并且它还提供了自动支持断点续传和范围请求等HTTP协议特性。

import os
from django.http import FileResponse

def download_file(request):
    file_path = '/path/to/my/file.txt'
    if os.path.exists(file_path):
        response = FileResponse(open(file_path, 'rb'))
        response['Content-Type'] = "application/octet-stream"
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(file_path))
        return response
    else:
        return HttpResponse("Sorry, the file you requested does not exist.")
# 通过将内容类型设置为 “application/octet-stream”,浏览器会提示用户保存或打开文件,而不是尝试在浏览器窗口中显示它。
  
 使用FileResponse对象时,Django会自动检测客户端是否支持范围请求(即断点续传),如果支持,它将启用自动断点续传功能。这意味着当用户暂停或取消下载时,他们可以在后续下载时从上次停止的地方继续。 
django 使用FileResponse限制文件下载大小

file_path = '/path/to/file'
file_size = os.path.getsize(file_path)
max_size = 10 * 1024 * 1024  # 10 MB

if file_size > max_size:
    content_range = 'bytes=0-{0}'.format(max_size - 1)
else:
    content_range = None

response = FileResponse(open(file_path, 'rb'), content_type='application/octet-stream', content_range=content_range)
如果文件大小超过了最大大小,就将 content_range 设置为 ‘bytes=0-{max_size-1}’,表示只传输前 10 MB 的数据;否则,将 content_range 设置为 None,表示传输整个文件。 

上传文件读取

Django 读取excel里的数据导入到数据库表中(使用第三方库openxl) 从Excel表批量导入数据到Django的数据库中一定要注意2条:

校验数据,因为Excel表格里的数据没有约束,经常会出现数据不符合数据表字段约束条件的情况,若不校验会导致大量数据读出来以后存数据库时报错,导致写进数据库的操作失败! 批量导入一定要开启事务。

开启事务的批量导入有2个特点:要么全部导入成功,要么全部导入失败。

django+xlsxwriter导出excel Xlsxwriter 使用 FileResponse类返回

利用序列化器实现增删改查接口

def user_list(request):
    if request.method =='GET':
        users= UserInfo.objects.all()
        serializer= UserInfoSerializer(users,many=True)         # many=True 代表序列化多条数据
        return JsonResponse(serializer.data,safe=False)
    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = UserInfoSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data,status=201)

def user_detail(request,id):
    try:
        user = UserInfo.objects.get(id=id)
    except UserInfo.DoesNotExist:
        return HttpResponse(status=404)
    if request.method == 'GET':
        serializer = UserInfoSerializer(user)
        return JsonResponse(serializer.data)
    elif request.method =='PUT':
        data = JSONParser().parse(request)
        serializer = UserInfoSerializer(user,data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors,status=400)
    elif request.method =='DELETE':
        user.delete()
        return HttpResponse(status=204)

url.py 实现
urlpatterns = [
    path('user/<int:id>/', views.user_detail()),
]

自定义序列化器的效验方法

规范:validate_字段名

# 方式1:
class UserInfoSerial(serializers.Serializer):
    def validated_pwd(self,value):
        if not 10< len(value)<20:
            raise serializers.ValidationError('字段的长度不在10-20位之间')
# 方式2:
def validated_pwd(self,value):
    if not 10< len(value)<20:
        raise serializers.ValidationError('字段的长度不在10-20位之间')
# 序列化器通过validators调用函数
pwd = serializers.CharField(validators=validated_pwd)

DRF定义请求和响应

"""
Django的request
request.GET # 获取get请求的参数
request.POST # 获取post请求传递的表单参数
put、patch  # post 请求传递的请求体参数(json格式),Django未定义其直接获取的方法
request.body.decode()
import json
params = json.loads(params)

DRF的request对象:
1. 对应的查询参数                request.query_params
2. 对应表单json参数获取(请求体)   request.data
"""

from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET','POST'])
def user_list1(request):
    return Response(data={'message':'OK'})

DRF 的Response对象:使用该类构造响应对象时,响应的具体内容会转化成符合前端需求的类型


from rest_framework.response import Response
return Response(data=None,status=None,template_name=None,headers=None,content_type=None)

API视图的装饰器

REST框架提供了两个可用编写的API视图的包装器:

  • 视图装饰器 @api_view
  • 类视图   APIView

@api_view实现增删改查的接口优化

from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET','POST'])
def user_list(request):
    if request.method =='GET':
        users= UserInfo.objects.all()
        serializer= UserInfoSerializer(users,many=True)         # many=True 代表序列化多条数据
        result = {'data':serializer.data,'message':'ok'}
        return Response(result, status.HTTP_201_CREATED)

    elif request.method == 'POST':
        serializer = UserInfoSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            result = {'data': serializer.data, 'message': 'ok'}
            return Response(result,status.HTTP_201_CREATED)
        result = {'data': serializer.errors, 'message': 'fail'}
        return Response(result,status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET','PUT','DELETE'])
def user_detail(request,id):
    try:
        user = UserInfo.objects.get(id=id)
    except UserInfo.DoesNotExist:
        return Response({'code':404,'message':'fail'},status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        serializer = UserInfoSerializer(user)
        return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)

    elif request.method =='PUT':
        data = JSONParser().parse(request)
        serializer = UserInfoSerializer(user,data=data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
        return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
    elif request.method =='DELETE':
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

使用DRF给url添加后缀:

  • 访问:/xxx.json 返回json格式
  • 访问:/xxx.api   访问DRF自带的接口调试页面

更新url文件

from django.urls import path
from . import views
from rest_framework.urlpatterns import  format_suffix_patterns
urlpatterns = [
    path('user/', views.user_list()),
    path('user/<int:id>/', views.user_detail()),
]
urlpatterns = format_suffix_patterns(urlpatterns)

# format_suffix_patterns 格式化数据 支持url添加后缀

# 更新views.py 添加参数format
def user_list(request,format=None)

类视图APIView

APIView和View的区别:

  • 传入到视图方法的是REST framework的Request对象
  • 视图返回的是REST framework的Resopnse对象
  • 任何APIException 异常会被捕捉,并处理成合适的响应信息
  • 扩展了身份认证、权限检查、流量控制三个功能

APIView实现增删改查的优化

from rest_framework.views import APIView

from rest_framework.parsers import JSONParser
from .models import UserInfo
from .serializers import UserInfoSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status


class UserListView(APIView):
    def get(self, request, format=None):
        users = UserInfo.objects.all()
        serializer = UserInfoSerializer(users, many=True)  # many=True 代表序列化多条数据
        result = {'data': serializer.data, 'message': 'ok', 'code': 201}
        return Response(result, status.HTTP_201_CREATED)

    def post(self, request, format=None):
        serializer = UserInfoSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            result = {'data': serializer.data, 'message': 'ok', 'code': 201}
            return Response(result, status.HTTP_201_CREATED)
        result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
        return Response(result, status=status.HTTP_400_BAD_REQUEST)


class UserDetailView(APIView):
    def get_object(self,id):
        try:
            return UserInfo.objects.get(id=id)
        except UserInfo.DoesNotExist:
            return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)

    def get(self, request, id, format=None):
        "获取单个资源"
        user = self.get_object(id)
        serializer = UserInfoSerializer(user)
        return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)

    def delete(self, request, id, format=None):
        user = self.get_object(id)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def put(self, request, id, format=None):
        user = self.get_object(id)
        serializer = UserInfoSerializer(user, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
        return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)

urls文件更新

from django.urls import path
from . import views
from rest_framework.urlpatterns import  format_suffix_patterns
urlpatterns = [
    path('user/<int:id>/', views.UserDetailView.as_view()),
    path('user/', views.UserListView.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)

APIView视图类的封装优化

class UserView(APIView):
    model = UserInfo # set model
    ser = UserInfoSerializer
    def get(self, request, format=None):
        users = self.model.objects.all()
        serializer = self.ser(users, many=True)  # many=True 代表序列化多条数据
        result = {'data': serializer.data, 'message': 'ok', 'code': 201}
        return Response(result, status.HTTP_201_CREATED)

    def post(self, request, format=None):
        serializer = self.ser(data=request.data)
        if serializer.is_valid():
            serializer.save()
            result = {'data': serializer.data, 'message': 'ok', 'code': 201}
            return Response(result, status.HTTP_201_CREATED)
        result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
        return Response(result, status=status.HTTP_400_BAD_REQUEST)


class UserDetailView(APIView):
    model = UserInfo # set model
    ser = UserInfoSerializer
    def get_object(self,id):
        try:
            return self.model.objects.get(id=id)
        except UserInfo.DoesNotExist:
            return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)

    def get(self, request, id, format=None):
        "获取单个资源"
        user = self.get_object(id)
        serializer = self.ser(user)
        return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)

    def delete(self, request, id, format=None):
        user = self.get_object(id)
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def put(self, request, id, format=None):
        user = self.get_object(id)
        serializer = self.ser(user, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
        return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
GenericAPIView视图的使用:继承APIView方法多了两个属性,继续优化
1. queryset = xxx.objects.all() 
2. serializer_class = xxxSerial
from rest_framework.generics import GenericAPIView

class UserView(GenericAPIView):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    def get(self, request, format=None):

        users = self.get_queryset()   # 同 self.queryset
        # serializer = self.get_serializer_class() 同 self.get_serializer
        serializer = self.get_serializer(users,many=True)

        result = {'data': serializer.data, 'message': 'ok', 'code': 201}
        return Response(result, status.HTTP_201_CREATED)

    def post(self, request, format=None):
        serializer =self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            result = {'data': serializer.data, 'message': 'ok', 'code': 201}
            return Response(result, status.HTTP_201_CREATED)
        result = {'data': serializer.errors, 'message': 'fail', 'code': 400}
        return Response(result, status=status.HTTP_400_BAD_REQUEST)


class UserDetailView(GenericAPIView):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    # def get_object(self,id):
    #     try:
    #         return self.model.objects.get(id=id)
    #     except UserInfo.DoesNotExist:
    #         return Response({'code': 404, 'message': 'fail'}, status=status.HTTP_404_NOT_FOUND)

    def get(self, request, id, format=None):
        "获取单个资源"
        user = self.get_object() # 同自定义get_object方法,优化
        serializer = self.get_serializer(user)
        return Response({'code': 204, 'message': serializer.data}, status=status.HTTP_204_NO_CONTENT)

    def delete(self, request, id, format=None):
        user = self.get_object()
        user.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def put(self, request, id, format=None):
        user = self.get_object()
        serializer = self.get_serializer(user, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'message': 'OK'}, status=status.HTTP_200_OK)
        return Response({'code': 400, 'message': 'fail'}, status=status.HTTP_400_BAD_REQUEST)
mixins视图集优化: 实现了self.get_serializer、self.get_object接口的实现可进一步封装

其主要的封装的视图

  • CreateModelMixin:提供create方法快速实现资源的创建
  • ListModelMixin: 提供list方法快速实现列表视图
  • RetrieveModelMixin: 获取单一数据,提供retrieve方法,快速返回一个存在的数据对象
  • UpdateModelMixin: 提供update方法快速更新一个存在的数据对象
  • DestroyModelMixin:提供destroy方法快速删除一个存在的数据对象
from rest_framework.generics import GenericAPIView,mixins

class UserView(GenericAPIView,mixins.ListModelMixin,mixins.CreateModelMixin):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    def get(self, request, *args,**kwargs):
        return self.list(request,*args,**kwargs) # 继承 ListModelMixin

    def post(self, request, *args,**kwargs):

        return self.create(request, *args,**kwargs) # 继承 CreateModelMixin


class UserDetailView(GenericAPIView,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer

    def get(self, request, *args,**kwargs):
        "获取单个资源"
        return self.retrieve(request, *args, **kwargs)  # 继承 RetrieveModelMixin

    def delete(self, request, *args,**kwargs):
        return self.destroy(request, *args, **kwargs)  # 继承 DestroyModelMixin

    def put(self, request, *args,**kwargs):
        return self.update(request, *args, **kwargs)  # 继承 UpdateModelMixin
视图扩展优化继承类
generics视图扩展类:进一步优化封装
  • CreateAPIView
  • ListAPIView
  • RetrieveAPIView
  • DestroyAPIView
  • UpdateAPIView
from rest_framework import status,generics

class UserView(generics.ListAPIView,generics.CreateAPIView):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    """
    ListAPIView # 封装get方法,省略
    CreateAPIView # 封装post方法,省略
    """


class UserDetailView(generics.RetrieveAPIView,generics.DestroyAPIView,generics.UpdateAPIView):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    """
    RetrieveAPIView # 封装get方法单一对象查询,省略
    DestroyAPIView  # 封装delete方法,省略
    UpdateAPIView   # 封装put方法,省略
    """

视图集:ViewSet视图不再实现get、post方法,而是实现动作action,如list(),create()一系列动作放到一个类中,而不产生冲突

  • list()  提供一组数据
  • retrieve()  提供单个数据
  • create  创建数据
  • update  保存数据
  • destory  删除数据

action属性: 只有使用as_view方法是,才会将action动作与请求响应

常见视图集类:

  • ViewSet ,继承自APIView ,提供了身份认证、权限效验、流量管理等接口(需要自定义action方法)
  • GenericViewSet 继承自GenericAPIView,提供了get_object、get_queryset方法
  • ModelViewSet继承自GenericAPIView,同时实现了CreateAPIView、ListAPIView、RetrieveAPIView、DestroyAPIView、UpdateAPIView方法
  • ReaOnlyModelViewSet继承自GenericAPIView,同时包括ListModelMixin、RetrieveModelMixin

上述使用ModelViewSet类视图集继续优化,代码效果同上

from rest_framework.viewsets import ModelViewSet

class UserView(ModelViewSet):
    queryset = UserInfo.objects.all() # set model
    serializer_class = UserInfoSerializer
    """
    已实现下列类视图,省略
    mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
    mixins.ListModelMixin,
    GenericViewSet
    """

# url路由更新
from django.urls import path
from . import views
from rest_framework.urlpatterns import  format_suffix_patterns
urlpatterns = [
    path('users/', views.UserView.as_view({'get':'list','post':'create'})),
    path('users/<int:pk>/', views.UserView.as_view({'get':'retrieve','delete':'destroy','put':'update'})),
]
urlpatterns = format_suffix_patterns(urlpatterns)

路由:Routers快速实现路由信息,下面两个区别是DefaultRouter会多附带一个默认的API根视图,返回所有列表视图

  • SimpleRouter-推荐
  • DefaultRouter

上面的url路由实现优化

from . import views
from rest_framework.urlpatterns import  format_suffix_patterns
from rest_framework import routers
# DRF的路由注册只支持视图集(当继承自ViewSet时使用)
router = routers.SimpleRouter()
router.register(r'users',views.UserView)
urlpatterns = []
urlpatterns +=router.urls

urlpatterns = format_suffix_patterns(urlpatterns)

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值