参考:https://www.cnblogs.com/wupeiqi/p/7805382.html

1 restful规范

https://www.ruanyifeng.com/blog/2014/05/restful_api.html

2 认证

  1. 问题:有些api需要用户登录才能访问,有些无需登录就能访问
  2. 基本使用——解决:
    1. 创建两张表
    2. 用户登录(返回token,并保存到数据库)

2.1 用户登录并生成token

models.py

  1. from django.db import models
  2. class UserInfo(models.Model):
  3. user_type_choices = (
  4. (1, '普通用户'),
  5. (2, 'VIP'),
  6. (3, 'SVIP'),
  7. )
  8. user_type = models.IntegerField(choices=user_type_choices)
  9. username = models.CharField(max_length=32, unique=True) # 用户名唯一
  10. password = models.CharField(max_length=64)
  11. class UserToken(models.Model):
  12. '''保存用户token'''
  13. # 一个用户对应一条token
  14. user = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
  15. token = models.CharField(max_length=64)

执行数据库迁移

应用api的urls.py

  1. from django.conf.urls import url
  2. from api import views
  3. app_name = 'api'
  4. urlpatterns = [
  5. url(r'^api/v1/auth/$',views.AuthView.as_view())
  6. ]

views.py

  1. from django.http import JsonResponse
  2. from rest_framework.views import APIView
  3. from api import models
  4. def md5(user):
  5. """token = 时间戳+md5(用户名)"""
  6. import hashlib
  7. import time
  8. ctime = str(time.time())
  9. m = hashlib.md5(bytes(user,encoding='utf-8'))
  10. m.update(bytes(ctime,encoding='utf-8'))
  11. return m.hexdigest()
  12. class AuthView(APIView):
  13. # APIView继承Django的view
  14. def post(self,request,*args,**kwargs):
  15. ret = {'code':1000,'msg':None}
  16. try:
  17. user = request.POST.get('username')
  18. pwd = request.POST.get('password')
  19. obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
  20. # 没有该用户
  21. if not obj:
  22. ret['code'] = 1001
  23. ret['msg'] = '用户名或密码错误'
  24. # 为登录用户创建token
  25. token = md5(user)
  26. # 存在就更新,不存在就创建
  27. models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
  28. ret['data'] = token
  29. except Exception as e:
  30. ret['code'] = 1002
  31. ret['msg'] = '请求异常'
  32. return JsonResponse(ret)
  • **def md5(user):**是生成用户token的方法,token = 时间戳 + md5(用户名),返回随机数,后期应该将这个方法写入工具类中
  • AuthView:继承rest_framework的APIView
  • 首先获取post方法中的用户名与密码,与数据库中比对,不存在该用户返回错误信息;如果存在该用户,为该用户生成token【新用户生成token,已登录的用户更新token:models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})

测试方法,使用postman,携带请求体:
image.png
数据库中生成token
image.png

2.2 基于token的认证

局部配置(视图级别)

使用步骤:

  1. 先定义一个认证类Authtication
  2. 再在需要认证的试图类中使用:

views.py中定义一个认证类

  1. from rest_framework import exceptions
  2. from rest_framework.authentication import BaseAuthentication
  3. from api import models
  4. class Authtication(BaseAuthentication):
  5. def authenticate(self,request):
  6. token = request.GET.get('token')
  7. token_obj = models.UserToken.objects.filter(token=token).first()
  8. if not token_obj:
  9. raise exceptions.AuthenticationFailed('用户认证失败')
  10. # 在rest framework内部,会将整个两个字段赋值给request,以供后续操作使用
  11. return (token_obj.user,token_obj)
  12. def authenticate_header(self, request):
  13. pass
  • 每个认证类必须实现这两个方法
  • 为了规范,每个认证类最好继承BaseAuthentication
  • def authenticate(self,request):自定义认证操作
  • def authenticate_header(self, request):认证失败时给浏览器返回的响应头

在视图类OrderView中使用
authentication_classes = [Authtication,]

  1. class OrderView(APIView):
  2. """订单相关业务"""
  3. authentication_classes = [Authtication,]
  4. def get(self,request,*args,**kwargs):
  5. # request.user
  6. # request.auth
  7. ret = {'code':1000,'msg':None}
  8. try:
  9. ret['data'] = ORDER_DICT
  10. except Exception as e:
  11. pass
  12. return JsonResponse(ret)

这样在访问 http://127.0.0.1:8000/api/v1/order/,如果不带token参数,返回:用户认证失败
image.png

带token:
image.png


配置全局认证

  1. 在当前应用下新建一个utils包,然后新建一个auth文件,将上述views.py中的Authtication类,放入auth文件中 ```python from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from api import models

class Authtication(BaseAuthentication):

  1. def authenticate(self,request):
  2. token = request.GET.get('token')
  3. token_obj = models.UserToken.objects.filter(token=token).first()
  4. if not token_obj:
  5. raise exceptions.AuthenticationFailed('用户认证失败')
  6. # 在rest framework内部,会将整个两个字段赋值给request,以供后续操作使用
  7. return (token_obj.user,token_obj)
  8. def authenticate_header(self, request):
  9. pass
  1. - `token_obj.user`:返回的是该token对应的**user对象**
  2. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1283987/1638863406451-054ad3cc-796f-4d77-8af9-b0b470a00527.png#clientId=ue2255359-2142-4&from=paste&height=288&id=u1ac922c3&margin=%5Bobject%20Object%5D&name=image.png&originHeight=576&originWidth=1512&originalType=binary&ratio=1&size=100917&status=done&style=none&taskId=ua6359443-e11e-4d28-ab86-028de642976&width=756)
  3. 2. 在**_settings.py_**
  4. ```python
  5. REST_FRAMEWORK = {
  6. # rest framework全局认证
  7. 'DEFAULT_AUTHENTICATION_CLASSES' : ['api.utils.auth.Authtication',],
  8. # 设置匿名用户
  9. "UNAUTHENTICATED_USER": None,
  10. "UNAUTHENTICATED_TOKEN": None,
  11. }
  • 其中DEFAULT_AUTHENTICATION_CLASSES列表中填写认证类的路径

image.png

  1. 视图views.py中直接写视图类就行,不需要使用authentication_classes = [Authtication,]

image.png

哪此时又产生一个问题,登录视图不需要认证,但此时已经配置全局认证,导致登录视图也需要认证,如果设置局部不需要认证?在不需要认真的视图中使用:

  1. authentication_classes = []

如登录视图不需要认证

  1. class AuthView(APIView):
  2. """用户登录认证"""
  3. authentication_classes = []
  4. def post(self,request,*args,**kwargs):
  5. ret = {'code':1000,'msg':None}
  6. try:
  7. user = request.POST.get('username')
  8. pwd = request.POST.get('password')
  9. obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
  10. # 没有该用户
  11. if not obj:
  12. ret['code'] = 1001
  13. ret['msg'] = '用户名或密码错误'
  14. token = md5(user)
  15. models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
  16. ret['data'] = token
  17. except Exception as e:
  18. ret['code'] = 1002
  19. ret['msg'] = '请求异常'
  20. return JsonResponse(ret)

源码流程:https://www.yuque.com/u1046159/auxwxv/qrt58h#ZM9x6

2.3 内置认证类(一般自定义)

image.png

  • 自定义认证类必须继承BaseAuthentication

    2.4 总结

  1. 使用
    1. 创建类,必须继承BaseAuthentication(**from **rest_framework.authentication **import **BaseAuthentication),必须实现以下这两个方法:其中只有authenticate方法自己写,另一个authenticate_header方法直接照抄,不用具体实现

image.png

  1. 返回值

    1. 抛出异常
    2. None,当前认证函数不管,交给下一个认证函数
    3. 返回一个元组(元素1,元素2),第一个参数赋值给request.user,第二个赋值给request.auth
  2. 局部使用:https://www.yuque.com/u1046159/lp12n4/ksnhgv#Xk1w0

  3. 全局使用:https://www.yuque.com/u1046159/lp12n4/ksnhgv#Wl2RA
  1. 源码流程:
    1. dispatch
      1. 封装request
        1. 获取定义的认证类(全局/局部),通过列表生成式创建对象
      2. initial
        1. perform_authentication
          1. request.user(内部循环….)

3 权限

为不同的用户赋予不同的权限

现在有一个需求:订单相关业务(只有SVIP可看)—OrderView

用户类型

  1. user_type_choices = (
  2. (1, '普通用户'),
  3. (2, 'VIP'),
  4. (3, 'SVIP'),
  5. )

views.py/OrderView

  1. class OrderView(APIView):
  2. """
  3. 订单相关业务(只有SVIP可看)
  4. """
  5. def get(self,request,*args,**kwargs):
  6. if request.user.user_type !=3:
  7. return HttpResponse('无权访问,只有SVIP可看!')
  8. ret = {'code':1000,'msg':None}
  9. try:
  10. ret['data'] = ORDER_DICT
  11. except Exception as e:
  12. pass
  13. return JsonResponse(ret)

当用户user_type不等于3时:
image.png
等于3时:
image.png


但此时视图与权限代码杂糅,有没有方法将权限判断代码抽离出来?有

3.1 局部配置

在工具包utils中新建python文件permission,编写权限函数MyPermission
api/utils/permission.py

  1. class MyPermission(object):
  2. message = '只有SVIP才能访问!'
  3. def has_permission(self,request,view):
  4. if request.user.user_type !=3:
  5. return False # 无权访问
  6. # 有权访问
  7. return True
  • message修改返回的消息

然后在需要权限配置的视图中使用

  1. from api.utils.permission import MyPermission
  2. class OrderView(APIView):
  3. """
  4. 订单相关业务(只有SVIP可看)
  5. """
  6. permission_classes = [MyPermission,]
  7. def get(self,request,*args,**kwargs):
  8. ret = {'code':1000,'msg':None}
  9. try:
  10. ret['data'] = ORDER_DICT
  11. except Exception as e:
  12. pass
  13. return JsonResponse(ret)
  • 引用包:from api.utils.permission import MyPermission
  • 设置权限:permission_classes = [MyPermission,]

可以写多个权限函数,然后根据实际需求,引用权限函数


3.2 全局配置

  1. REST_FRAMEWORK = {
  2. "DEFAULT_PERMISSION_CLASSES":['api.utils.permission.MyPermission',],
  3. }

同基于token的认证的全局配置

3.3 源码流程:https://www.yuque.com/u1046159/auxwxv/qrt58h#eEeGJ

4 访问频率控制(自定义)

需求:限制用户ip,60s内只能访问3次
思路:

  1. 定义一个字典,字典的键设置为IP,字典的值为该IP 的访问时间,为一个列表。将用户ip以及访问时间保存下来
  2. 如果用户首次访问,将用户当前ip以及访问时间加入字典中,并返回true(表示未达到访问限制)
  3. 如果用户非首次访问,从字典中获取用户历史记录(包含ip以及访问时间),判断history有值,并且把时间间隔大于60秒的都pop掉(history.pop()默认移除列表中最后一个元素,即最早访问时间);小于60的继续放在里面,最后对列表的长度进行整体判断
  4. 假如列表的长度大于3,说明60秒内访问的次数大于3次,我们就限制它的访问


4.1 局部配置

在utils包下面新建一个throttle文件,里面写VisitThrottle类

  1. VISIT_RECORD = {}
  2. class VisitThrottle(object):
  3. """访问频率限制:10s内只能访问3次"""
  4. def __init__(self):
  5. self.history = None
  6. def allow_request(self, request, view):
  7. # 1.获取用户ip
  8. remote_addr = request.META.get('REMOTE_ADDR')
  9. # 2.当前时间
  10. ctime = time.time()
  11. # 首次访问
  12. if remote_addr not in VISIT_RECORD:
  13. VISIT_RECORD[remote_addr] = [ctime, ]
  14. return True
  15. # 非首次访问
  16. history = VISIT_RECORD.get(remote_addr)
  17. self.history = history
  18. while history and history[-1] < ctime - 10:
  19. history.pop()
  20. if len(history) < 3:
  21. history.insert(0, ctime)
  22. return True
  23. def wait(self):
  24. """还需等多少秒才能访问"""
  25. # 当前时间
  26. ctime = time.time()
  27. return 60 - (ctime - self.history[-1])
  • VISIT_RECORD = {}:全局变量,用于保存用户ip以及访问时间,此处有一个问题。当程序重启时,全局变量被清空,但django rest framework默认将其放入缓存中
  • remote_addr = request.META.get('REMOTE_ADDR'):rest framework中自带获取当前用户ip
  • 必须实现两个方法allow_requestwait;allow_request方法进行访问逻辑判断,wait方法当访问频率达到限制时,提示还需等多少秒才能访问
  • 视图类中使用throttle_classes = [VisitThrottle]引用访问控制类

视图类中引用

  1. from api.utils.throttle import VisitThrottle
  2. class AuthView(APIView):
  3. throttle_classes = [VisitThrottle]
  4. def post(self, request, *args, **kwargs):
  5. #其他

下面是访问被限制
image.png

4.2 全局配置

在utils包下面新建一个throttle文件,里面写VisitThrottle类,同上
settings.py

  1. REST_FRAMEWORK = {
  2. "DEFAULT_THROTTLE_CLASSES":['api.utils.throttle.VisitThrottle'],
  3. }

4.3 源码流程 https://www.yuque.com/u1046159/auxwxv/qrt58h#xitgy

4.4 内置类实现访问频率控制

自定义类继承BaseThrottle

  1. from rest_framework.throttling import BaseThrottle

image.png
代码改造

  1. from rest_framework.throttling import BaseThrottle
  2. VISIT_RECORD = {}
  3. class VisitThrottle(BaseThrottle):
  4. """访问频率限制:10s内只能访问3次"""
  5. def __init__(self):
  6. self.history = None
  7. def allow_request(self, request, view):
  8. # 1.获取用户ip
  9. remote_addr = self.get_ident(request)
  10. # 2.当前时间
  11. ctime = time.time()
  12. # 首次访问
  13. if remote_addr not in VISIT_RECORD:
  14. VISIT_RECORD[remote_addr] = [ctime, ]
  15. return True
  16. # 非首次访问
  17. history = VISIT_RECORD.get(remote_addr)
  18. self.history = history
  19. while history and history[-1] < ctime - 10:
  20. history.pop()
  21. if len(history) < 3:
  22. history.insert(0, ctime)
  23. return True
  24. def wait(self):
  25. """还需等多少秒才能访问"""
  26. # 当前时间
  27. ctime = time.time()
  28. return 60 - (ctime - self.history[-1])
  • remote_addr = request.META.get('REMOTE_ADDR')改为remote_addr = self.get_ident(request)

4.5 更简单的实现方法

以上都是自定义类,rest framework里面自带一个内置的SimpleRateThrottle

  1. 控制类

    1. class VisitThrottle(SimpleRateThrottle):
    2. # key
    3. scope = 'visit'
    4. def get_cache_key(self, request, view):
    5. # 返回用户ip
    6. return self.get_ident(request)
  • 定义一个类,继承SimpleRateThrottle
  • 需要给一个scope字段,当做唯一标识key来使用
  • get_cache_key方法返回用户ip
  1. 在settings.py中配置 ```python REST_FRAMEWORK = { “DEFAULT_THROTTLE_CLASSES”:[‘api.utils.throttle.VisitThrottle’], “DEFAULT_THROTTLE_RATES”:{
    1. "visit":'3/m'
    } }
  1. - 配置当前控制类的位置:DEFAULT_THROTTLE_CLASSES
  2. - 设置访问频率:DEFAULT_THROTTLE_RATES,**visit**是控制类中的scope字段(唯一标识),**3/m**表示一分钟只能访问三次
  3. ---
  4. <a name="cGjOM"></a>
  5. ## 4.6 补充
  6. 以上都是对匿名用户进行访问控制,那想要同时对匿名用户和登录用户就进行访问控制,应该如何实现?
  7. ```python
  8. class VisitThrottle(SimpleRateThrottle):
  9. # key
  10. scope = 'visit'
  11. def get_cache_key(self, request, view):
  12. # 返回用户ip
  13. return self.get_ident(request)
  14. class UserThrottle(SimpleRateThrottle):
  15. scope = 'user'
  16. def get_cache_key(self, request, view):
  17. return request.user.username

配置

  1. REST_FRAMEWORK = {
  2. # 登录用户控制访问全局配置
  3. "DEFAULT_THROTTLE_CLASSES":['api.utils.throttle.UserThrottle'],
  4. "DEFAULT_THROTTLE_RATES":{
  5. "visit":'3/m',
  6. "user":'10/m',
  7. }
  8. }

views.py

  1. class AuthView(APIView):
  2. """用户登录认证"""
  3. authentication_classes = []
  4. permission_classes = []
  5. throttle_classes = [VisitThrottle]
  6. def post(self, request, *args, **kwargs):
  7. # ....

5 版本

5.1 url中通过GET传参(一般不用)

自定义写法

  1. class ParamVersion():
  2. def determine_version(self, request, *args, **kwargs):
  3. version = request.GET.get('version')
  4. return version

然后在试图类中引用

  1. class UsersView(APIView):
  2. versioning_class = ParamVersion
  3. def get(self,request,*args,**kwargs):
  4. print(request.version)
  5. return HttpResponse('用户列表')
  • versioning_class = ParamVersion

    使用内置类

    引用:from rest_framework.versioning import QueryParameterVersioning
    versioning_class = QueryParameterVersioning ```python from rest_framework.versioning import QueryParameterVersioning

class UsersView(APIView):

  1. versioning_class = QueryParameterVersioning
  2. def get(self,request,*args,**kwargs):
  3. print(request.version)
  4. return HttpResponse('用户列表')
  1. `QueryParameterVersioning`中可以从配置文件中配置三个参数<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1283987/1639013363646-39b78c13-0de4-4d55-a0af-7ffadb2f1f13.png#clientId=ub05fc64e-40fe-4&from=paste&height=114&id=u0e34d547&margin=%5Bobject%20Object%5D&name=image.png&originHeight=228&originWidth=1227&originalType=binary&ratio=1&size=36062&status=done&style=none&taskId=u683d9a38-9b4f-414a-b628-07259e17c41&width=613.5)
  2. ```python
  3. default_version = api_settings.DEFAULT_VERSION
  4. allowed_versions = api_settings.ALLOWED_VERSIONS
  5. version_param = api_settings.VERSION_PARAM

settings.py

  1. REST_FRAMEWORK = {
  2. "DEFAULT_VERSION":"v1",
  3. "ALLOWED_VERSIONS":['v1,v2'],
  4. "VERSION_PARAM":"version",
  5. }

5.2 在url路径中传参(推荐)

局部配置

引用

  1. from rest_framework.versioning import URLPathVersioning

urls.py配置

  1. from django.urls import re_path
  2. from api2 import views
  3. app_name = 'api2'
  4. urlpatterns = [
  5. # path('api2/users/',views.UsersView.as_view()),
  6. re_path(r'^api2/(?P<version>[v1|v2]+)/users/$',views.UsersView.as_view()),
  7. ]
  • 上述的url路径中使用正则表达式

views.py

  1. from rest_framework.versioning import URLPathVersioning
  2. class UsersView(APIView):
  3. versioning_class = URLPathVersioning
  4. def get(self,request,*args,**kwargs):
  5. print(request.version)
  6. return HttpResponse('用户列表')

image.png

image.png


全局配置

settings.py

  1. REST_FRAMEWORK = {
  2. "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
  3. }

然后视图类中不需要再设置versioning_class = URLPathVersioning

  1. from rest_framework.versioning import URLPathVersioning
  2. class UsersView(APIView):
  3. def get(self,request,*args,**kwargs):
  4. print(request.version)
  5. return HttpResponse('用户列表')

5.3 反向生成url

使用django rest framework

  1. request.versioning_scheme.reverse(viewname='api2:user',request=request)
  • 当有多个应用,注意viewname写法

views.py
image.png

urls.py

  1. from api2 import views
  2. app_name = 'api2'
  3. urlpatterns = [
  4. re_path(r'^api2/(?P<version>[v1|v2]+)/users/$',views.UsersView.as_view(),name="user"),
  5. ]

访问:http://127.0.0.1:8000/api2/v1/users/,后台打印结果:

  1. http://127.0.0.1:8000/api2/v1/users/

使用django自带

  1. u2 = reverse(viewname='api2:user',kwargs={'version':1})
  • 需要传参:版本号

6 解析器

6.1 django自带的解析器

django:request.POST / request.body

  1. 请求头要求:

    1. Content-Type: "application/x-www-form-urlencoded"

    ps:如果请求头中的Content-Type: “application/x-www-form-urlencoded” ,request.POST中才有值(去request.body中解析数据)

  2. 数据格式要求:

    1. name=alex&age=18

    如:

    1. form表单提交
    2. ajax提交

image.png

6.2 rest framework解析器使用

局部使用

  1. class ParserView(APIView):
  2. from rest_framework.parsers import JSONParser
  3. parser_classes = [JSONParser,]
  4. def post(self, request, *args, **kwargs):
  5. """允许用户发送json格式"""
  6. print(request.data)
  7. return HttpResponse('parser')
  • JSONParser表示只能解析application/json 请求头
  • FormParser: 表示只能解析 application/x-www-form-urlencoded 请求头
  • 最常用的就是json,前后端交互一般使用json格式
  • 用的时候才解析,即上述代码使用request.data调用:
    • 使用流程:(1)获取用户请求头(2)获取用户请求体(3)根据用户请头和parser_classes = []中支持的请求头进行比较,谁符合交给谁处理(4)JSONParser对象处理请求体(5)处理后赋值给request.data

此时访问:
image.png
后端能获取到前端传递的json格式,如果不是json格式就报错:
image.png

全局配置(一般使用全局配置)
在settings.py中配置

  1. REST_FRAMEWORK = {
  2. "DEFAULT_PARSER_CLASSES": ["rest_framework.parsers.JSONParser", "rest_framework.parsers.FormParser"]
  3. }

后端返回的格式
image.png

除了上述解析器:还有其他解析器:https://www.cnblogs.com/shenjianping/p/11509858.html,比如文件上传FileUploadParser,全局配置后,若想要某个视图函数支持文件解析,需要局部配置:

  1. parser_classes = [FileUploadParser,]

image.png

6.3 rest framework解析器原理

https://www.cnblogs.com/wdliu/p/9128990.html

总结

  1. 使用的时候进行全局配置
  2. 使用request.data获取值
  3. 本质:

    1. 请求头
    2. 状态码
    3. 请求方法
      1. 若面试说到本质可能会问上述abc
  4. 源码流程

7 序列化

参考:https://www.cnblogs.com/welan/p/10151714.html

比如当进行数据库查询的时候,django查询的结果是一个对象QuerySet

  1. class RoleView(APIView):
  2. def get(self, request, *args, **kwargs):
  3. roles = models.Role.objects.all()
  4. print(roles)
  5. return HttpResponse(roles)

我们一般需要转化为json对象返回给前端
转换方法一般有以下方式:https://blog.csdn.net/shirukai/article/details/81086242
django自带的serializers序列化model

  1. def edit(request):
  2. # ajax传值
  3. m_number = request.GET.get('m_number')
  4. inventory= Inventory.objects.filter(m_number=m_number)
  5. json_data = serializers.serialize('json', inventory)
  6. return HttpResponse(inventory, content_type="application/json")

django rest framework中使用

方式一

首先定义一个序列化serializers

  1. from rest_framework import serializers
  2. class RoleSerializer(serializers.Serializer):
  3. id = serializers.IntegerField()
  4. titile = serializers.CharField()

然后在查询中使用

  1. class RoleView(APIView):
  2. def get(self, request, *args, **kwargs):
  3. roles = models.Role.objects.all()
  4. ser = RoleSerializer(instance=roles,many=True)
  5. ret = json.dumps(ser.data,ensure_ascii=False)
  6. return HttpResponse(ret)
  • ser.data就是序列化的结果

返回结果:

  1. [{"id": 1, "titile": "老师"}, {"id": 2, "titile": "学生"}, {"id": 3, "titile": "护士"}]

但是上述方法略显麻烦:定义模型类后,还要定义一个RoleSerializer,重复写模型类中字段id、titile

方式二

创建一个名为 api2/serializers.py的文件,来用作我们的数据表示。
api2/serializers.py

  1. from rest_framework import serializers
  2. from api2.models import Role
  3. class RoleSerializer(serializers.ModelSerializer):
  4. class Meta:
  5. model = Role
  6. fields = '__all__'

views.py

  1. from api2.serializers import RoleSerializer
  2. class RoleView(APIView):
  3. def get(self, request, *args, **kwargs):
  4. roles = models.Role.objects.all()
  5. ser = RoleSerializer(instance=roles,many=True)
  6. ret = json.dumps(ser.data,ensure_ascii=False)
  7. print(ret)
  8. return HttpResponse(ret)

!!!怎么感觉还不如直接使用django自带的序列化呢!!!!

以上返回的字段可以自定义显示!

序列化深度控制

  • depth建议取值:0~4

image.png

自定义验证字段

8 分页

未分页前:
serializers.py

  1. from rest_framework import serializers
  2. from inventory.models import Inventory
  3. class InventorySerializer(serializers.ModelSerializer):
  4. class Meta:
  5. model = Inventory
  6. fields = '__all__'

views.py

  1. from inventory.serializers import InventorySerializer
  2. class InventoryView(APIView):
  3. def get(self, request, *args, **kwargs):
  4. inventories = models.Inventory.objects.all()
  5. serializers = InventorySerializer(instance=inventories, many=True)
  6. ret = json.dumps(serializers.data,ensure_ascii=False)
  7. return HttpResponse(ret)

查询结果将数据库结果全部返回,数据量大很卡

8.1 看第n页,每页显示n条数据

8.2 在某个位置,向后查看n条数据

8.3 加密分页,上一个和下一页

9 视图

参考:https://www.jianshu.com/p/3cec36add17d

9.1 GenericAPIView(一般不用)

9.2 GenericViewSet

9.3 ModelViewSet

9.4 总结

  • 完成基本的增删改查 ModelViewSet
  • 增删 CreateModelMixin,DestroyModelMixin
  • 复杂的逻辑:GenericViewSet或者APIV