目录
回顾
一、drf入门
1.前后端开发模式
前后端分离:drf方便我们大人们方便我们快速写出接口
前后端混合:bbs 模板语法
2. API接口:前后端交互的媒介
3.接口测试工具:postman
4.restful规范十条
5.drf快速入门
6.必须继承APIView写视图类
- View的执行流程:cbv的执行流程
路由中:视图类.as_view() --> 本质是:View的as_view内部的view闭包函数中的dispatch
,根据请求方式执行视图函数中的方法 - APIView的执行流程
路由中:视图类.as_view() --> 本质是:APIView的as_view去掉csrf,调用父类的as_view
请求来了,执行的是去掉了csrf的View的as_view内的view闭包函数
self.dispatch --> APIView
--包装了新的request
--执行三大认证
--处理全局异常 - 新的Request
- 包装了老的request:request._request
- 为了使新的request和原来的使用方法一致:重写了
__getattr__
- 新的方法(伪装成了属性):
data
body中提交的数据都在里面 query_params
:地址栏中的数据- 文件、其他都没有差别
二、序列化组件
1.功能
-
帮助我们快速实现:
序列化
、反序列化
、数据校验
-
如何定义:
-
写一个序列化类继承(Serializer/ModelSerizlizer)
-
写要序列化的字段(字段类,字段参数:read_only,write_only)
-
字段自己的规则:局部钩子、全局钩子
-
序列化修改字段格式:
-
序列化中写SerializerMethodField,get_字段名
-
表模型中写方法(返回字典Dict Field、列表ListField)
-
json格式字符串必须用"",如{"name":"zhang","age":16},如果是{'name':'zhang','age':16}就不是json格式,js识别不了。
-
在字典中则""和''都可以正常字典使用。
-
-
-
在视图类中使用
# 继承Serializer写序列化类 ser = BookSerializer(instance=要序列化的对象,many=True) ser = BookSerizlizer(data=request.data) ser = BookSerializer(instance=要修改的对象,request.data) ser.data 序列化后的数据,字典格式 校验数据: 错误数据:ser.errors ser.save():通过判断instance是否为空,觉得调用的是create还是update 如果继承了Serializer,必须重写create和update # 继承ModelSerializer写序列化类 1.class Meta: model=表模型 fields='__all__'[新增的字段一定要在这里注册] extra_kwargs={'name':{read_only:True}} # 对字段进行添加 2.重写某个字段 3.序列化修改字段格式跟之前一样 4.一般不需要重写create和update 一次性提交的数据涉及多个表时可能会需要重写 (但是如果数据中能明确对应表关系的话也可以不重写,比如数据值有author_id) 5.注意:直接从表模型中映射的字段也有字段类和字段属性
三、请求与响应
-
请求对象,响应对象(Request,Response)
-
原生django响应头里写内容
响应对象[内容]
-
drf能够解析的请求格式:局部配置和全局配置
-
drf的响应格式:局部配置和全局配置
四、视图类
1.两个视图基类
- APIView
- GenericAPIView:继承了APIView,有几个属性和方法
queryset = None # 要序列化的数据
serializer_class = None # 序列化类
lookup_field = 'pk' # 针对单条数据的过滤
get_queryset() # 获取要序列化的数据,比self.queryset扩展性高
get_object() # 获取单个对象
get_serializer() # 获取序列化类对象
2. 5个视图扩展类
- ListModelMixin
- CreateModelMixin
- RetrieveModelMixin
- UpdateModelMixin
- DestoryModelMixin
需要配合GenericAPIView用
3. 9个视图子类
- ListAPIView
- CreateAPIView
- ListCreateAPIView
- RetrieveAPIView
- UpdateAPIView
- DestoryAPIView
- RetrieveUpdateAPIView
- RetrieveDestoryAPIView
- RetrieveUpdateDestoryAPIView
视图类,继承了GenericaAPIView+5个视图扩展类之几+get/post/delete/put
4.视图集
-
ViewSetMixin
重写了as_view,一旦继承了它及其子类,路由写法改变,as_view中加字典做映射
{'get':'list','put':'update'}
-
ViewSet = ViewSetMixin+APIView
class TestView(ViewSet): def login(self,request): pass
-
GenericViewSet=ViewSetMixin+GenericAPIView
class TestView(GenericViewSet): queryset = None serializer_class = None def login(self,request): pass
-
ModelViewSet
路由写法改变,两个类属性:queryset,serializer_class
-
ReadOnlyModelViewSet
路由写法改变,两个类属性:queryset,serializer_class
只有读取所有和获取单条,没有增加、修改
今日内容
一、路由
只要继承了ViewSetMixin及其子类的视图类,路由都可以换个写法
例如:path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'}))
1.自动生成路由
# urls.py
from django.contrib import admin
from django.urls import path, include
from app01 import views
# drf提供两个路由类,以后继承了ViewSetMixin及其子类的视图类,路由都可以使用这两个路由来自动生成
# 自动生成路由步骤
# 第一步:导入
from rest_framework.routers import SimpleRouter, DefaultRouter
# 第二步:实例化
router = SimpleRouter()
# router = DefaultRouter() # 区别是DefaultRouter会多一个根路径^$ [name='api-root']
# 第三步:注册路由(可以注册多个)
# 注册参数:路径、视图类、别名(可以不写)
router.register('books', views.BookView,'books')
router.register('publish', views.BookView)
router.register('user', views.BookView)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls))
]
'''
第四步:把自动生成的路由添加到urlpatterns中
方式一:path('', include(router.urls))
方式二:urlpatterns += router.urls
'''
# urlpatterns += router.urls
-
SimpleRouter 和DefaultRouter的区别
虽然看起来多了很多,实质上就是DefaultRouter会多一个
根路径
^$ [name='api-root']-
router = SimpleRouter()
-
router = DefaultRouter()
-
3.action装饰器的使用
二、登录接口编写
1.models.py
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=16)
def __str__(self):
return self.username
# 用户登录记录表
# 区分用户是否登录
class Token(models.Model):
token = models.CharField(max_length=32, null=True)
# 如果用户没有登录token为空,如果登录了就会有值,登录多次保留最后一次
user = models.OneToOneField(to='User', on_delete=models.DO_NOTHING)
2.views.py
from rest_framework.response import Response
from rest_framework.decorators import action
'''
注意:
继承ViewSetMixin及其子类的视图类都可以自动生成路由
但是映射关系是定死的(get:list,post:create,get:retrieve,put:update,delete:destroy)
自己想做映射关系需要使用装饰器action
'''
import uuid # 随机产生字符串
class UserView(ViewSetMixin, APIView):
@action(methods=['POST', ], detail=False, url_path='login')
def login(self, request):
res = {'code': 100, 'msg': '登陆成功'}
# 取出前端传入的用户名密码,校验通过:返回登陆成功;校验失败:返回登录失败
username = request.POST.get('username')
password = request.POST.get('password')
print(username, password)
user = User.objects.filter(username=username, password=password).first()
if user:
# 登陆成功,每个用户生成的token都不同,把token保存到Token表中
token = uuid.uuid4()
'''
生成随机字符串(永不重复)
如果Token没有记录就新增,如果有就更新
通过user去Token表中查数据:
能查到:使用defaults的数据更新,
查不到:直接通过user和defaults的数据新增
'''
Token.objects.update_or_create(defaults={'token': token}, user_id=user.id)
res['token'] = token
return Response(res)
else:
res['code'] = 101
res['msg'] = '用户名或密码错误'
return Response(res)
3.urls.py
from django.contrib import admin
from django.urls import path, include
from app01 import views
from rest_framework.routers import SimpleRouter, DefaultRouter
router = SimpleRouter()
router.register('user', views.UserView, 'user')
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls)),
]
三、on_delete
- CASCADE:级联删除
- PROTECT:保护模式,采用该选项,删除时会抛出
ProtectedError
错误。 - SET_NULL:置空模式,删除的时候,外键字段被设置为空
- SET_DEFAULT:置默认值,删除的时候,外键字段设置为默认值
- SET:自定义一个值
on_delete=None
# 删除关联表中的数据时,当前表与其关联的field的行为
on_delete=models.CASCADE
# 删除关联数据,与之关联也删除
on_delete=models.DO_NOTHING
# 删除关联数据,什么也不做
on_delete=models.PROTECT,
# 删除关联数据,引发错误ProtectedError
models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL,
# 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
# models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
on_delete=models.SET_DEFAULT,
# 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
on_delete=models.SET(值),
# 删除关联数据,与之关联的值设为指定的值
四、认证
1.需求
访问接口,必须登录后才能访问
2.通过认证完成,使用步骤
-
写一个认证类:LoginAuth,继承
BaseAuthentication
-
重写
authenticate
方法,在内部做认证 -
认证通过:返回两个值(当前用户 token)
-
认证失败:抛
AuthenticationFailed
异常 -
只要返回了两个值,后续的request.user 就是当前登录用户
-
如果想让某个视图类登录后才能访问
# 方式一: class TestView(): authentication_classes = [LoginAuth, ] # 方式二: 全局配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth', ] } 局部禁用: class TestView(): authentication_classes = []
3.认证类
from .models import Token
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 在这里做认证,校验用户是否登录(带了token并且能查到就是登录,返回两个数据值,否则就是没登录抛异常)
# 用户带的token如何获取?==> 后端人员设定:放在请求地址中
token = request.GET.get('token')
# 通过token查询该token是否在表中有记录
user_token = Token.objects.filter(token=token).first()
if user_token:
return user_token.user, token # 返回两个值:当前用户 token
else:
raise AuthenticationFailed('您没有登录')
标签:序列化,models,视图,token,drf,路由,delete
From: https://www.cnblogs.com/Zhang614/p/16770292.html