3小时搞定DRF框架 | Django REST framework前后端分离框架实践
前言(基于INSCODE AI助手)
DRF(全称Django REST framework)是一个用于构建 Web API 的强力工具集,是一个基于Django的Python Web框架,它为开发人员提供了一套快速开发 RESTful API 的工具,它能够自动化 API 可视化、文档化,实现接口的自动化测试以及自动化的API路由、序列化、视图、验证、分页、版本管理、认证等等功能。DRF简化了API的开发,并提供了一系列的工具来构建高质量的API。
1.1:课程介绍
学习目标:使用DRF开发RESTful API接口
学习内容:序列化、视图集、路由、认证、权限
课程效果:DRF的多种视图实现课程信息的增删改查
2.1: 从四个方面理解前后端分离
- 交互形式
RESTful API是i前后端约定好的接口规范
- 代码组织方式 前后端不分离:django模板语法 前后端半分离 前后端分离
- 开发模式 前后端不分离项目开发流程: 前后端分离项目开发流程:
- 数据接口规范流程
2.2 深入理解什么是RESTful API
可以学习别人的接口规范学习。
例如:
github-API
深入理解什么是RESTful API
2.3 Pycharm搭建项目开发环境
- Settings.py
# 因为RESTframework是有前端文件的,后面使用时会全部放到这个目录
STATIC_ROOT = os.pardir.join(BASE_DIR,"static")
STATICFILES_DIRS =[
os.path.join(BASE_DIR,"staticfiles")]
- manage.py
makemigrations
migrate
createsuperuser
2.4 framework介绍和安装
django rest framework官网:https://www.django-rest-framework.org/
按照文档执行下面步骤:
- 1.安装相应包
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
- 在settings.py中修改配置
# Add 'rest_framework' to your INSTALLED_APPS setting.
INSTALLED_APPS =[..."rest_framework",# 用于开发RESTful API'rest_framework.authtoken',# DRF自带的Token认证]
对于rest framework所有相关配置都放在settings的一个字典里面
# DRF的全局配置
REST_FRAMEWORK ={'DEFAULT_PAGINATION_CLASS':'rest_framework.pagination.PageNumberPagination',# 自带分页类'PAGE_SIZE':50,# 每页数据量'DATETIME_FORMAT':'%Y-%m-%d %H:%M:%S',# 时间显示格式'DEFAULT_RENDER_CLASSES':['rest_framework.renders.JSONRenderer','rest_framework.renders.BrowsableAPIRenderer',],# 返回response对象所用的类'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser','rest_framework.parsers.MultiPartParser',],# 解析器,如何解析request请求中的request.data'DEFAULT_PERMISSION_CLASSES':['rest_framework.permissions.IsAuthenticated',],# 权限相关配置'DEFAULT_AUTHENTICATION_CLASSES':['rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.TokenAuthentication',],# 认证相关配置"URL_FIELD_NAME":'link',}
- 在urls.py中修改配置
urlpatterns =[...
path('api-auth/', include('rest_framework.urls'))# DRF的登录退出]
- DRF的20个模块 序列化、视图、路由、认证、权限、限流、过滤、解析器、渲染器、分页、版本、测试、概要、异常处理、配置、验证、状态码、内容协商、缓存、元数据
3.1 开发课程信息模型类
models.py
from django.db import models
# Create your models here.from django.db import models
from django.conf import settings
classCourse(models.Model):
name = models.CharField(max_length=255, unique=True, help_text='课程名称', verbose_name='名称')
introduction = models.TextField(help_text='课程介绍', verbose_name='介绍')
teacher = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, help_text='课程讲师', verbose_name='讲师')
price = models.DecimalField(max_digits=6, decimal_places=2, help_text='课程价格')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')classMeta:
verbose_name ="课程信息"
verbose_name_plural = verbose_name
ordering =('price',)def__str__(self):return self.name
将字段注册到后台,方便从admin后台添加数据
admin.py
from django.contrib import admin
from.models import Course
# Register your models [email protected](Course)classCourseAdmin(admin.ModelAdmin):
list_display =('name','introduction','teacher','price')
search_fields = list_display
list_filter = list_display
3.2 什么是序列化
序列化也叫序列化器,是指把查询集QuerySet或者模型类实例instance这种django的数据类型转化为json或者xml
把queryset或者instance转化为方便前端可以轻松渲染的json/xml/yaml
所以序列化和反序列化是为了前后端数据交互
深度剖析 Django 的 serializer
- 启动项目,进入admin后台,插入数据
- 在python console中测试django的序列化器
from course.models import Course
from django.core import serializers
serializers.serialize('json', Course.objects.all())# '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门", "introduction": "快速入门Django REST framework,学会开发一套自己的Restful API服务,并且自动生成API文档", "teacher": 1, "price": "9.99", "created_at": "2023-07-28T10:11:46.882", "update_at": "2023-07-28T10:11:46.882"}}]'# 如果只需要序列化一部分字段
serializers.serialize('json', Course.objects.all(), fields=("name"))# '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门"}}]'
但django的序列化器还有很多需要完善的地方
1.验证处理:在反序列化的过程中,当前端传递过来的数据放在request.data里时,要转化为模型类实例,然后保存。这时需要对前端提交的数据进行验证。
2.验证器的参数
3.同时序列化多个对象
4.序列化的过程中添加上下文
5.没有对无效的数据异常处理
6.关系型字段的外键字段只返回了id,需要我们自己处理关系型字段
drf的序列化器可以帮我们很好的解决这些问题。
3.3 如何继承ModelSerializer序列化模型类
Python学习————序列化器(复习
在应用下建一个serializes.py
模型类的序列化的写法和django开发时form的写法非常类似
先回顾给模型类建form表单类
from django import forms
from rest_framework import serializers # 导入序列化器from.models import Course
classCourseForm(forms.ModelForm):classMeta:
model = Course
fields =('name','introduction','teacher','price')
模型类序列化的写法几乎一样,只是继承自serializers.ModelSerializer
teacher是外键,所以想得到讲师对应的名字,需要把用户的名称序列化出来。
teacher关联到的用户表,并不是新建课程时新建一个用户,所以该字段可以设为只读ReadOnlyField
classCourseSerializer(serializers.ModelSerializer):
teacher = serializers.ReadOnlyField(source='teacher.username')# 外键字段、只读classMeta:
model = Course # 写法和上面的CourseForm类似# exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")# fields = ('name', 'introduction', 'teacher', 'price')
fields ="__all__"
同样方法序列化用户模型类
ModelSerializer是更高一级的封装,它继承自Serializer,要实现比较灵活的自定义,可以继承自Serializer
我们这里只序列化模型类,比较简单,所以可以直接用
from django.contrib.auth.models import User
classUserSerializer(serializers.ModelSerializer):classMeta:
model = User
fields ="__all__"
对外键字段的序列化,可以指定遍历的深度
如果表结构有子表关联到父表,父表又关联到另外的父表,就可以设置深度
classCourseSerializer(serializers.ModelSerializer):
teacher = serializers.ReadOnlyField(source='teacher.username')# 外键字段、只读classMeta:
model = Course # 写法和上面的CourseForm类似# exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")# fields = ('name', 'introduction', 'teacher', 'price')
fields ="__all__"
depth =2# 深度
3.4 带URL的HyperlinkedModelSerializer
假设请求课程信息时,希望每条课程信息的记录,都能跳转到详情页
DRF相关的配置,都写在settings.py中的REST_FRAMEWORK的字典中
继承自HyperlinkedModelSerializer
fields里加上url
url是默认值,如果要改成其他名称,如“link”,可在settings.py中设置URL_FIELD_NAME使全局生效
settings.py
# DRF的全局配置
REST_FRAMEWORK ={'DEFAULT_PAGINATION_CLASS':'rest_framework.pagination.PageNumberPagination',# 自带分页类'PAGE_SIZE':50,# 每页数据量'DATETIME_FORMAT':'%Y-%m-%d %H:%M:%S',# 时间显示格式'DEFAULT_RENDER_CLASSES':['restframework.renders.JSONRenderer','restframework.renders.BrowsableAPIRenderer',],# 返回response对象所用的类'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONparser','rest_framework.parsers.Formparser','rest_framework.parsers.MultiPartparser',],# 解析器,如何解析request请求中的request.data'DEFAULT_PERMISSION_CLASSES':['rest_framework.permissions.IsAuthenticated',],# 权限相关配置'DEFAULT_AUTHENTICATION_CLASSES':['rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.TokenAuthentication',],# 认证相关配置"URL_FIELD_NAME":'link',}
serializers.py
classCourseSerializer(serializers.HyperlinkedModelSerializer):
teacher = serializers.ReadOnlyField(source='teacher.username')# 外键字段、只读classMeta:
model = Course # 写法和上面的CourseForm类似# url是默认值,可在settings.py中设置URL_FIELD_NAME使全局生效# fields = ('id', 'url', 'name', 'introduction', 'teacher', 'price', 'created_at', 'update_at')
fields =('id','link','name','introduction','teacher','price','created_at','update_at')
4.1 Django的views开发RESTful API接口
通过DRF使用四种不同的方式来Restful API接口
- 函数式编程
- 类视图
- 通用类视图
- DRF的视图集
在views.py文件中
4.1.1 Django原生的view-函数式编程编写API接口
思路就是判断这个是什么方法,然后进行处理
@csrf_exemptdefcourse_list(request):
course_dict ={'name':'课程名称','introduction':'课程介绍','price':0.11}if request.method =="GET":# return HttpResponse(json.dumps(course_dict), content_type='application/json')return JsonResponse(course_dict)# 这两种写法是等价的if request.method =="POST":
course = json.loads(request.body.decode('utf-8'))return JsonResponse(course, safe=False)# 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false
需要注意:post请求,需要使用装饰器来解除csrf限制
4.1.2 Django原生的view-类视图编程编写API接口
CBV的编写思路是对不同的请求方法用对应的函数处理
import json
from django.http import JsonResponse, HttpResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
# Django CBV 编写API接口@method_decorator(csrf_exempt, name='dispatch')classCourseList(View):defget(self, request):return JsonResponse(course_dict)@csrf_exemptdefpost(self, request):
course = json.loads(request.body.decode('utf-8'))return JsonResponse(course, safe=False)# 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false
可以导入方法装饰器,装饰的方法是是dispatch,因为根据django的请求响应原理,当request请求来的时候,它首先到达dispatch方法,通过dispatch方法处理后,再找到post方法
上面的两种方式,是直接使用原生的Django写接口,有很多东西都需要自己从零开始实现。
比如分页、排序、认证、权限、限流等等
于是就有了DRF的视图,集成了这些接口开发常用的功能
4.2 DRF的装饰器api_view - 函数式编程
4.2.1 实现“获取所有课程信息或新增一个课程”的接口
- 新建drf的fbv视图
from rest_framework.decorators import api_view
from rest_framework.response import Response # django使用的是JsonResponse或HttpResponse,而drf直接封装好了,就是Responsefrom rest_framework import status
from.models import Course
from.serializers import CourseSerializer
"""一、函数式编程 Function Based View"""@api_view(["GET","POST"])defcourse_list(request):"""
获取所有课程信息或新增一个课程
:param request:
:return:
"""if request.method =="GET":
s = CourseSerializer(instance=Course.objects.all(), many=True)# 序列化多个对象,所以需要many=True# 序列化后的数据可以通过s.data获得return Response(data=s.data, status=status.HTTP_200_OK)elif request.method =="POST":
s = CourseSerializer(data=request.data, partial=True)# 反序列化, partial=True表示部分更新if s.is_valid():
s.save(teacher=request.user)# 讲师是只读属性return Response(data=s.data, status=status.HTTP_201_CREATED)return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)
函数式编程会用到装饰器
partial=True表示部分更新
- 新建路由
为了方便管理course这个app下的路由,在course这个应用下创建一个urls.py文件,然后通过include包含到项目的urls中
django urls include用法
course/urls.py
from django.urls import path
from course import views
urlpatterns =[# Function Based View
path("fbv/list/", views.course_list, name="fbv-list")]
drf_tutorial/urls.py
urlpatterns =[
path('api-auth/', include('rest_framework.urls')),# DRF的登录退出
path("admin/", admin.site.urls),
path('course/', include('course.urls'))]
先不用HyperlinkedModelSerializer的api了,因为HyperlinkedModelSerializer是高度集成的序列化类,后面使用drf的视图集来编程可以用。所以序列化类改用:
classCourseSerializer(serializers.ModelSerializer):
teacher = serializers.ReadOnlyField(source='teacher.username')# 外键字段、只读classMeta:
model = Course # 写法和上面的CourseForm类似# exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")# fields = ('name', 'introduction', 'teacher', 'price')
fields ="__all__"
depth =2# 深度
- 返回结果
- 测试post请求
4.2.2 实现“获取一个课程信息或更新删除某个课程信息”的接口
- 实现视图
@api_view(["GET","PUT","DELETE"])defcourse_detail(request, pk):# 通过url传递pk"""
获取、更新、删除一个课程
:param request:
:param pk:
:return:
"""try:
course = Course.objects.get(pk=pk)except Course.DoesNotExist:return Response(data={"msg":"没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)else:if request.method =="GET":
s = CourseSerializer(instance=course)# 序列化一个对象不需要many=Truereturn Response(data=s.data, status=status.HTTP_200_OK)elif request.method =="PUT":# PUT方法表示更新,部分写法和POST方法类似
s = CourseSerializer(instance=course, data=request.data)#instance是指要序列化哪个实例,data表示数据哪里来的# 表示把data的数据,反序列化之后,保存或者更新到cuorse对象里if s.is_valid():
s.save()# 不需要teacher字段return Response(s.data, status=status.HTTP_200_OK)elif request.method =="DELETE":
course.delete()return Response(status=status.HTTP_204_NO_CONTENT)
- 实现路由
urlpatterns =[# Function Based View
path("fbv/list/", views.course_list, name="fbv-list")
path("fbv/detail/<int:pk>", views.course_detail, name="fbv-detail")]
4.3 如何使用Postman测试API接口(我这里是apipost)
我这里以apipost为例
认证方式:
- basic auth认证:账户名、密码认证
- api key认证:token认证
- OAuth 2.0等
要在请求头加一些key,value,可以点header
query是url带上的参数
后端代码里解析的request.data,一般是放在raw里面
- Post请求
- Get请求
4.4 DRF中的视图APIView - 类视图编程
4.4.1 实现“获取所有课程信息或新增一个课程”的接口
- 导入APIView
from rest_framework.views import APIView
- 实现类视图
"""二、类视图 Class Based View"""classCourseList(APIView):defget(self, request):"""
:param request:
:return:
"""
queryset = Course.objects.all()
s = CourseSerializer(instance=queryset, many=True)return Response(s.data, status=status.HTTP_200_OK)defpost(self, request):"""
:param request:
:return:
"""
s = CourseSerializer(data=request.data)if s.is_valid():
s.save(teacher=self.request.user)print(type(request.data),type(s.data))# type(request.data): <class 'dict'># type(s.data): <class 'rest_framework.utils.serializer_helpers.ReturnDict'>return Response(data=s.data, status=status.HTTP_201_CREATED)return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
- 新建路由
urlpatterns =[# Function Based View
path("fbv/list/", views.course_list, name="fbv-list"),
path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),# Class Based View
path("cbv/list/", views.CourseList.as_view(), name='cbv-list')]
- 测试请求
4.4.2 实现“详情页”的接口
静态方法:无论是通过类对象直接调用还是实例对象进行调用都是可以的,需要注意的是在静态方法中无法使用实例属性和方法
python静态方法、实例方法、类方法使用
- 实现接口
classCourseDetail(APIView):@staticmethod# 静态方法defget_object(pk):"""
:param pk:
:return:
"""try:return Course.objects.get(pk=pk)except Course.DoesNotExist:returndefget(self, request, pk):"""
:param request:
:param pk:
:return:
"""
obj = self.get_object(pk=pk)ifnot obj:return Response(data={"msg":"没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj)return Response(s.data, status=status.HTTP_200_OK)defput(self, request, pk):
obj = self.get_object(pk=pk)ifnot obj:return Response(data={"msg":"没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
s = CourseSerializer(instance=obj, data=request.data)if s.is_valid():
s.save()return Response(data=s.data, status=status.HTTP_200_OK)return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)defdelete(self, request, pk):"""
:param request:
:param pk:
:return:
"""
obj = self.get_object(pk=pk)ifnot obj:return Response(data={"msg":"没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
obj.delete()return Response(status=status.HTTP_204_NO_CONTENT)
- 实现路由
urlpatterns =[# Function Based View
path("fbv/list/", views.course_list, name="fbv-list"),
path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),# Class Based View
path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
path("cbv/detail/<int:pk>/", views.CourseDetail.as_view(), name='cbv-detail'),]
- 测试请求
类视图编程方法和函数式编程的编写方法,代码几乎一样。下一小节讲解更加简洁的编写方法。
4.5 DRF中的通用类视图GenericAPIView
导入generics
from rest_framework import generics
4.5.1 实现查看和请求新增的接口
通用类视图,实际上是把一些常见的增删改查操作对应的类通过mixin把他混合在一起。
这里属性的名称是固定的
这里需要重载perform_create方法
4.5.2 实现课程详情的接口
- 实现通用类视图
下面的写法等价于
class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
不过对于下面的方法,请求的方法不再是GET、PUT、PATCH、DELETE,而是retrieve,update,destory等,所以还是建议用
class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
from rest_framework import mixins
from rest_framework.generics import GenericAPIView
classGCourseDetail(generics.mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
- 新增路由
urlpatterns =[# Function Based View
path("fbv/list/", views.course_list, name="fbv-list"),
path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),# Class Based View
path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
path("cbv/detail/<int:pk>/", views.CourseDetail.as_view(), name='cbv-detail'),# Generic Class Based View
path("gcbv/list/", views.GCourseList.as_view(), name='gcbv-list'),
path("gcbv/detail/<int:pk>/", views.GCourseDetail.as_view(), name='gcbv-detail'),]
- 测试请求
通用类视图里面还做好了其他事情:总个数(count)、下一页(next)、上一页(previous)、数据(results)
4.6 DRF的viewsets开发课程信息的增删改查接口 - 视图集
- 导入viewsets
from rest_framework import viewsets
- 创建视图集
"""四、DRF的视图集"""classCourseViewSet(viewsets.ModelViewSet):
queryset = Course.objects.all()
serializer_class = CourseSerializer
defperform_create(self, serializer):
serializer.save(teacher=self.request.user)
不做权限认证只需要四行代码
4.7 Django的URLs与DRF的Routers
- 新增路由
写法和前面不一样
两种视图集的路由写法
- 1 传统写法
# DRF viewsets
path("viewsets/", views.CourseViewSet.as_view({"get":"list","post":"create"}), name="viewsets-list"),
path("viewsets/<int:pk>/", views.CourseViewSet.as_view({"get":"retrieve","put":"update","patch":"partial_update","delete":"destory"}), name="viewsets-detail")
- 2.DRF的路由routers
- 导入
from rest_framework.routers import DefaultRouter
router = DefaultRouter()# 把类实例化
router.register(prefix="viewsets", viewset=views.CourseViewSet)# 把视图集注册到这个路由实例里面
urlpatterns =[
path("", include(router.urls))]
- 测试接口
5.1 DRF认证方式介绍
DRF常用的三种认证方式:
1.BasicAuthentication:用户名密码认证
2.SessionAuthentication:Session认证
3.TokenAuthentication:Token认证
也可以实现自定义的认证方案,或者使用第三方的包,比如json webtoken(关于jwt的认证,会在接下来的drf进阶实战课程讲解)
认证和权限的区别:
认证是对用户登录的身份进行校验
权限指的是一个登录验证通过的用户,他能够访问哪些接口;或者对于某一个接口,他能够拿到什么级别的数据
根据Django restframework对http request的响应流程来看,身份认证是发生在权限检查和限流检查之前的
认证和权限,核心依赖两个数据:request.user, request.auth
认证机制实际上依赖的是Django的auth框架
对'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ],
中的多个认证类,DRF会按顺序从上往下对每个类进行认证。并使用第一个成功通过的认证类来返回值,来设置request.user和request.auth
5.1.1 BasicAuthentication
设置basicauthentication,则headers会多一个authorization,它是用户名密码经过base64库计算出来的密文,这是postman自动完成的。base64库不具有机密性,是可以解密的。所以basicauthentication一般用于测试工作,不用于生产环境
- 测试,通过basicauthentication认证后,request.user和request.auth返回什么
print(self.request.user, self.request.auth)print(type(self.request.user),type(self.request.auth))# admin None# <class 'django.contrib.auth.models.User'> <class 'NoneType'>
- 查看响应头有什么信息 密码正确 密码错误
认证失败的话会在响应头里面多一个WWW_Authenticate字段
5.1.2 SessionAuthentication
使用的是Django默认的会话后端,通常在前端js里使用http,ajax请求时可以使用session认证,使用这个时,需要给后端提供csrf令牌的。
5.1.3 TokenAuthentication
是一种简单的,基于令牌的http认证方式
- 在settings.py的INSTALLED_APPS加上
'rest_framework.authtoken'
会生成一张数据表
INSTALLED_APPS =["django.contrib.admin","django.contrib.auth","django.contrib.contenttypes","django.contrib.sessions","django.contrib.messages","django.contrib.staticfiles","rest_framework",# 用于开发RESTful API'rest_framework.authtoken',# DRF自带的Token认证'course.apps.CourseConfig',]
- 生成token的方式
5.1.3.1 使用Django manag.py生成Token
只能供管理员测试
手动生成token
python manage.py drf_create_token admin #给admin建一个token
5.1.3.2 使用Django的信号机制生成Token
目的:
自动生成token
用户可以通过接口请求到token
view.py中
from django.db.models.signals import post_save # 保存之后,即用户已经建好之后的信号from django.conf import settings
from django.dispatch import receiver # 接收信号from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)defgenerate_token():
也可以直接导入django的user模型类作为认证模型类:
from django.contrib.auth.models import User
原理:当User模型类新建一个实例并把并保存的时候,即新建一个用户的时候,因为保存要调用save方法
保存之后,post_save信号会传递给receiver,receiver接受之后,就会执行函数generate_token
执行函数时,instance是指新建的用户实例,created=True,于是在authtoken_token表中生成一条记录
给用户生成的token,用户如何获取到呢?
rest_framework已经帮我们写好了,我们直接调用即可
在总的路由urls.py中
from django.contrib import admin
from django.urls import path, include
from rest_framework.authtoken import views
urlpatterns =[
path("api-token-auth/", views.obtain_auth_token),# 获取token的接口
path('api-auth/', include('rest_framework.urls')),# DRF的登录退出
path("admin/", admin.site.urls),
path('course/', include('course.urls'))]
- 测试-新建用户 user01 - mima123456 可以看到token表中有新增记录
- 测试,通过postman,通过接口获取token
- 认证成功 请求头
print(self.request.user, self.request.auth)print(type(self.request.user),type(self.request.auth))# user01 e1e4eb90e389feb76c8bb71ad73e3b3c63e8090c# <class 'django.contrib.auth.models.User'> <class 'rest_framework.authtoken.models.Token'>
认证成功的话,request.user依旧是django的user类实例
request.auth是Token类实例
响应头里面没有和认证有关的信息
- 认证失败
- 要对某一个接口,去使用不同的认证的方式
不论使用什么视图编程方式,都有对应的设置方法。下面按照四种不同的视图编程方式,分别讲解。
- 1.对函数式编程 导入对于认证的装饰类:
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication
装饰器是有顺序的
对象上只添加密码认证的类装饰器
@api_view(["GET","POST"])@authentication_classes((BasicAuthentication,))# 对象级别的认证设置,优先于全局设置defcourse_list(request):"""
获取所有课程信息或新增一个课程
:param request:
:return:
"""if request.method =="GET":
s = CourseSerializer(instance=Course.objects.all(), many=True)# 序列化多个对象,所以需要many=True# 序列化后的数据可以通过s.data获得return Response(data=s.data, status=status.HTTP_200_OK)elif request.method =="POST":
s = CourseSerializer(data=request.data, partial=True)# 反序列化, partial=True表示部分更新if s.is_valid():
s.save(teacher=request.user)# 讲师是只读属性return Response(data=s.data, status=status.HTTP_201_CREATED)return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)
- 测试
注意写法,必须是
Token xxx
- 2.对类视图编程 直接加入类属性
authentication_classes
- 2.对类视图编程 直接加入类属性
classCourseList(APIView):
authentication_classes =(BasicAuthentication, SessionAuthentication, TokenAuthentication)
通用类视图、视图集也是一样的,也都有类属性
5.3 DRF的权限控制
常用的权限类有哪些?应该如何设置权限策略?如何自定义对象级别权限?
DRF的权限都是在permissions模块里面,权限检查的过程和前面讲解的身份认证一样,也是会使用request.user和request.auth属性中的身份认证信息来决定请求是否传入。、
5.3.1 在settings.py中可以设置全局的权限类
- 常用权限类有:
IsAuthenticatedOrReadOnly: 登录的用户可以增删改查,不登陆的用户可以查询
IsAuthenticated:只有登录的用户可以进行所有操作,不登陆的用户不能进行所有操作,get也不行
IsAdminUser:admin用户有权限访问接口,是不是admin是看auth_user表的is_staff字段,true表示是admin级别用户
AllowAny:允许所有请求
5.3.2 如何在接口上/对象级别设置权限
- 导入装饰器
from rest_framework.decorators import api_view, authentication_classes, permission_classes
- 导入权限类
在这里插入代码片
5.3.2.1 给函数视图设置权限
- 给函数视图加上装饰器
@api_view(["GET","POST"])@authentication_classes((BasicAuthentication,))# 对象级别的认证设置,优先于全局设置@permission_classes((IsAuthenticated,))# 自定义的权限类defcourse_list(request):
5.3.2.2 给类视图/通用类视图/视图集设置权限
- 直接加入类属性
authentication_classes
permission_classes =(IsAuthenticated,)
5.3.3 如何自定义对象级别权限?
实现只能修改自己的信息,别人的信息只可以查看,不能修改。
- 在应用下面建立permission.py,并创建自定义的权限类 permission.py
classIsOwnerReadOnly(permissions.BasePermission):"""
自定义权限:只有对象的所有者可以增删改查
"""defhas_object_permission(self, request, view, obj):# 重写BasePermission的方法"""
所有的request请求都有读权限,因此一律允许GET/HEAD/OPTIONS方法
如果用户是自己,可以修改
:param request:
:param view:
:param obj:
:return: bool
"""if request.method in permissions.SAFE_METHODS:returnTrue# 对象的所有者才有写权限return obj.teacher == request.user
重写
has_object_permission
方法
安全的方法("GET", "HEAD", "OPTIONS")
可以用
permissions.SAFE_METHODS
代替
- 将创好的自定义权限类导入视图
from.permission import IsOwnerReadOnly
classGCourseList(generics.ListCreateAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
permission_classes =(IsAuthenticated,)defperform_create(self, serializer):
serializer.save(teacher=self.request.user)classGCourseDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer
permission_classes =(IsAuthenticated, IsOwnerReadOnly)
- 测试接口
6.1 如何生成API接口文档
6.1.1 如何生成API接口文档
通过请求url可以查看单个接口的格式等信息。但是有没有方法展示所有接口信息,即API在线文档
这样能方便前端查看,一目了然
下面操作必须要先pip install coreapi
- 1.在settings.py的REST_FRAMEWORK中加入
REST_FRAMEWORK ={'DEFAULT_SCHEMA_CLASS':'rest_framework.schemas.AutoSchema',...}
- 2.在总的urls.py中添加路由 先导入get_schema_view 再创建get_schema_view实例 再创建路由
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title="DRF API文档", description="xxx")
urlpatterns =[
path("api-token-auth/", views.obtain_auth_token),# 获取token的接口
path('api-auth/', include('rest_framework.urls')),# DRF的登录退出
path("admin/", admin.site.urls),
path('course/', include('course.urls')),
path('schema/', schema_view),]
- 测试
建议在Chrome应用商店下载jsonView插件
点击GET-corejson
但是文档还是不够美观,下一节介绍使用coreapi的概要功能
6.2 DRF的概要使用方法介绍
coreapi应该如何配置,以及文档的使用方法。
- 修改REST_FRAMEWORK的’DEFAULT_SCHEMA_CLASS’属性
- 在urls.py中
- 1.导入模块,新增路由
from rest_framework.documentation import include_docs_urls
urlpatterns =[
path("api-token-auth/", views.obtain_auth_token),# 获取token的接口
path('api-auth/', include('rest_framework.urls')),# DRF的登录退出
path("admin/", admin.site.urls),
path('docs/', include_docs_urls(title='DRF API文档', description='Django REST framework快速入门')),
path('course/', include('course.urls')),]
- 测试
在这个API文档中,认证配置好之后,刷新之后需要重新配置
7.1 课程总结
- 应该使用哪种视图开发? 使用函数式视图编写灵活,但是这是面向过程的方式,重复率高 使用类视图,可以用到python中类的特性,封装、继承、多态,减少代码重复率 通用类视图,灵活度就比较低了 视图集高度定制化,灵活度最低 一般以类视图编程为主。
- DRF的运行机制?APIView源码?测试?缓存?限流。。。都没有讲到
版权归原作者 N刻后告诉你 所有, 如有侵权,请联系我们删除。