跨域同源

django做跨域同源 需要把csrf去掉 跨站请求伪造

同源

  1. 同源机制:域名、协议、端口号相同的同源

简单请求

  1. 不写头部请求 跨域会拦截报错缺少请求信息
  2. 1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么putdelete等肯定是非简单请求)
  3. HEAD
  4. GET
  5. POST
  6. 2HTTP的头信息不超出以下几种字段:(如果比这些请求头多,那么一定是非简单请求)
  7. Accept
  8. Accept-Language
  9. Content-Language
  10. Last-Event-ID
  11. Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vueaxios默认的请求体信息格式是json的,ajax默认是urlencoded的。
  12. #vue.js axios -- $.ajax ajax和axios都是基于js的封装框架
  13. 支持跨域,简单请求
  14. 服务器设置响应头:Access-Control-Allow-Origin = '域名' '*'

复杂请求

不在简单范围内的请求头和请求方法

写法

  1. access-contorl-allow-origin 请求头
  2. 写了斜杠http//127.0.0.1/ 只能路径之后才可以访问
  3. 直接写ip地址http//127.0.0.1 是全路径下
  4. 复杂请求有option请求 进行预警’
  5. contype是规定以什么格式进行上传
  6. 支持跨域,复杂请求
  7. 由于复杂请求时,首先会发送“预检”请求'options'请求方法,如果“预检”成功,则发送真实数据。
  8. “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  9. “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  10. res['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8001'
  11. res['Access-Control-Allow-Headers'] = 'content-type'#请求头部信息
  12. # res['Access-Control-Allow-Methods'] = 'PUT'#请求方法
  13. # res['Access-Control-Allow-Origin'] = '*
  14. 全部网址都可以进行访问
  15. 请求头部信息是需要按照 指定的要求文件格式

GIT版本管理工具

集中式的版本管理工具 是把所有项目上线到项目中 集中管理 蹦了之后项目就崩了

分布式 可以直接把整个版本down下来进行开发 但是你开发的东西基于其他人就没办法进行操作 又要等着上传

drf

问题

前后端分离

  1. 1.常用vue.js
  2. 2.后端给前端json数据
  3. 3.后端要想使用drf组件**request.data
  4. 4.需要前端返回json数据类型
  5. 5.self封装了request属性
  6. self.request.method

移动端盛行

PC端应用

  1. crm项目,前端后端一起写,运行在浏览器上

第二部分 任务

以前会使用很多url绑定视图函数返回

  1. http://127.0.0.1:8000/info/get/
  2. http://127.0.0.1:8000/info/add/
  3. http://127.0.0.1:8000/info/update/
  4. http://127.0.0.1:8000/info/delete/

请求方法

  1. http://127.0.0.1:8000/info/
  2. get,获取数据
  3. post,添加
  4. put,更新
  5. delete,删除

现在要遵循restful规范

  1. restful是什么
  2. resultful是一种前后端约定俗称的一种规则,用于程序之间进行数据交换的约定
  3. 详细说明
  4. 1url中一般用名词:httpwwwbaidu.com/article/面向资源编程,网络上东西都视为资源
  5. 1.5筛选条件在url参数中进行传递例如
  6. #http://www.baidu.com/article/?page=1&category
  7. 2.是一套规则,用于程序之间进行数据交换的约定。
  8. 3.他规定了一些协议,对我们感受最直接的的是,以前写增删改查需要写4个接口,restful规范的就是1 个接口,根据method的不同做不同的操作,比如:
  9. 4.get/post/delete/put/patch/delete. 初次之外,resetful规范还规定了:
  10. - 数据传输通过json
  11. 扩展:前后端分离、app开发、程序之间(与编程语言无关)
  12. 5- URL中一般用名词:
  13. http://www.luffycity.com/article/ (面向资源编程,网络上东西都视为资源)
  14. 6建议加上api标识
  15. url写法
  16. http://www.luffycity.com/api/v1....(建议,因为他不会存在跨域的问题)
  17. 注意:版本还可以放在请求头中 http://www.luffycity.com/api/ accept: ...
  18. 7建议用https代替http
  19. #为了保证数据的安全
  20. 9.要返回给用户状态码(建议)
  21. from rest_formwork import status
  22. status.HTTP_200_OK 返回状态码
  23. 或者在字典里面返回自定义code状态码
  24. #例data{
  25. # code:10000
  26. status:radom_string
  27. #}
  28. - 200,成功
  29. - 300301永久 /302临时
  30. - 400403拒绝 /404找不到
  31. - 500,服务端代码错误
  32. 10新增的数据返回值(建议)
  33. 要返回多个列表套字典格式
  34. GET HTTP:..WWW.xxx.com/api/user/
  35. [
  36. {"id":1,"name":"xxx","age":19}
  37. {"id":1,name}
  38. ]
  39. 单条返回字典
  40. 11 操作异常要返回错误信息
  41. {
  42. error"Invalid API key"
  43. }
  44. 12 对于下一个请求要返回一些接口:Hypermedia AP
  45. {
  46. 'id':2,
  47. 'name':'alex',
  48. 'age':19,
  49. 'depart': "http://www.luffycity.com/api/user/30/"
  50. }

json数据:

  1. JSON: {
  2. name:'alex',
  3. age:18,
  4. gender:'男'
  5. }

以前用webservice,数据传输格式xml

  1. 以前用webservice,数据传输格式xml
  2. XML
  3. <name>alex</name>
  4. <age>alex</age>
  5. <gender>男</gender>

使代码更加专业

不使用drf框架

返回json类型数据

  1. django创建一个项目叫做api '接口'
  2. 通过jsonresopnese(data,safe=Flase)
  3. jsonresopnese默认支持字典 非字典需要使用safe

约定俗成的返回数据要返回json类型

只使用一个url cbv格式

  1. #只使用一个url cbv格式
  2. get 获取数据
  3. post添加
  4. put更新
  5. patch局部更新
  6. delete删除 请求方法

基于django可以实现遵循restful规范的接口开发规范

  • fbv 实现比较麻烦
  • cbv 相比较fbv比较简单 根据method做了不同的区分
  • 使用drf比较方便

初识drf

  1. drf是一个基于django开发的组件,本质是一个djangoapp drf可以办我们快速开发出一个遵循restful规范的程序

写接口的时候用到drf

视图

使用CBV

  1. from django.views import View
  2. 之前django是继承view
  3. 继承apiview
  4. from rest_framework import Apiview
  5. from rest_framework.views import APIView

知识点

  1. 继承apiview
  2. 1.请求来了先执行视图的dispatch方法
  3. 2.版本处理
  4. 3.认证
  5. 4.权限
  6. 5.节流
  7. 6.解析器
  8. '''
  9. -解析器,根据用户请求体格式不同进行数据解析,解析之后放在request.data中
  10. 如果content-type:x-www-urlencoded,那么drf会根据 & 符号分割的形式去处理请 求体。 user=wang&age=19
  11. 如果content-type:application/json,那么drf会根据 json 形式去处理请求体。
  12. {"user":"wang","age":19}
  13. '''
  14. 7.序列化
  15. '''
  16. - 序列化serlizer类 .data,可以对QuerySet进行序列化,也可以对用户提交的数据进行校验。
  17. '''
  18. 8.筛选器
  19. 9.分页
  20. 10.渲染器
  21. - 渲染器,可以帮我们把json数据渲染到页面上进行友好的展示。(内部会根据请求设备不同做不同的 展示)

1.安装地址

  1. pip3 install djangorestframework

2.需要先注册app!!!

如果有新建的app也需要进行注册,要不然不识别

admin不会自动加载

model数据库表结构也不会执行同步

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'rest_framework'
  9. ]

3.写路由


  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from api import views
  4. urlpatterns = [
  5. url(r'^drf/info/', views.DrfInfoView.as_view()),
  6. ]
  7. #as_view()执行as_view方法和函数一样执行

4.写视图上

然后进行引用 模块

内置response代替了 django的jsonresponse

  1. from django.shortcuts import render
  2. from rest_framework.response import Response
  3. from rest_framework.views import APIView
  4. from hula import models
  5. # Create your views here.
  6. class DrfCategoryView(APIView):
  7. def post(self, request, *args, **kwargs):
  8. #接收 有名传参(关键字传参) 无名传参(位置传参)
  9. obj = request.POST.get('data')
  10. if obj:
  11. models.Category.objects.create(**obj)
  12. return Response('OK成功')

知识点总结

resful规范

  1. #基于cbv操作 也就是视图类
  2. 1.给别人提供一个URL,根据URL请求方式的不同,做不同操作。
  3. get,获取
  4. post,增加
  5. put,全部更新
  6. patch,局部更新
  7. delete,删除
  8. 2.数据传输基于json格式。
  9. 潜规则
  10. 因为不论什么请求方式,都需要给前端返回对象内容,就是json格式的
类的约束
  1. 如果出现 NOTmplementedError错误 说明必须实现实现发
  2. 方法

drf框架

  1. 不基于drf也可以是实现resful规范来开发接口程序
  2. 使用drf之后,可以快速帮我们开发resful规范来开发接口

初始化数据库

1.迁移数据库

  1. 外键需要使用为空或者给一个默认值
  2. blank=True Null=True

2.url路由

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from api import views
  4. urlpatterns = [
  5. url(r'^drf/category/', views.DrfCategoryView.as_view()),
  6. ]
  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. class DrfCategoryView(APIView):
  4. pass

3.FBV

接口:访问接口时,创建一个文章类型(post增加)

  1. from django.shortcuts import render
  2. from rest_framework.response import Response
  3. from rest_framework.views import APIView
  4. from hula import models
  5. # Create your views here.
  6. class DrfCategoryView(APIView):
  7. def post(self, request, *args, **kwargs):
  8. #接收 有名传参(关键字传参) 无名传参(位置传参)
  9. obj = request.POST.get('data')
  10. if obj:
  11. models.Category.objects.create(**obj)
  12. return Response('OK成功')

假设写后端

4.开发完毕告诉前端访问

  1. http://127.0.0.1:8000/drf/category/

5.模拟前端访问数据下载软件postman

默认使用x-www-urlencoded

拼接成 value&value

  1. requesr.body获取请求体
  2. request.POST获取的是POST请求的所有数据
  3. #字典类型
  4. #QueryDict: {'title': ['摩擦'], 'id': ['1']}>
  5. request.body: name=alex&age=19&gender=12
  6. request.POST: {'name': ['alex'], 'age': ['19'], 'gender': ['12']}

使用raw原生json发送

json(一般使用json)

注意点
  1. #request.body获取是bytes类型
  2. request.body: b'{"id":1,"name":"ALEX","AGE"}'
  3. 1.decode解码成json字符串
  4. 2.loads成可以给python处理的字典(json序列化)
  5. json.loads(request.body.decode('utf-8'))
  6. #json格式字符串是双引号
前端json的值
  1. requesr.body获取请求体里面的数据
  2. request.POST获取的是POST请求的所有数据
  3. request.body: b'{"ID":1,"name":"Alex","age":19}'
  4. request.POST: 没有值

drf使用

对象类型转换成字典类型

  1. from django.forms import model_to_dict
  2. model_to_dict#转换
  3. obj = models.Category.objects.filter(pk=pk).first()
  4. obj=model_to_dict(obj)

默认封装了 request.data(django没有) 进行了解码序列化

  1. 视图 APIview
  2. request.data中有一个解析器
  3. 解析器,根据用户请求体格式不同进行数据解析,解析之后方法
  4. 在进行解析时候,drf会读取http

路径

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls),
  3. url(r'^info/$', views.InfoView.as_view()),
  4. url(r'^drf/info/$', views.DrfInfoView.as_view()),
  5. url(r'^drf/category/$', views.DrfCategoryView.as_view()),
  6. url(r'^drf/category/(?P<pk>\d+)/$', views.DrfCategoryView.as_view()),
  7. ]

直接全部文章get

  1. class DrfCategoryView(APIView):
  2. def get(self,request,*args,**kwargs):
  3. #obj=models.Article.objects.values()
  4. #obj=models.Article.objects.all()
  5. # obj=models.Article.objects.all.values('id','name')
  6. obj=list(obj)
  7. return Response(obj)

?format=json 可以直接序列化json

单独的文章发送

不使用序列化器

  1. from django.forms import model_to_dict
  2. model_to_dictmodel对象转换成字典
  3. def get(self,request,*args,**kwargs):
  4. pk=kwargs.get('pk')
  5. # print(1)
  6. if not pk:#判断有没有取到值
  7. obj=models.Article.objects.values()
  8. # obj=models.Article.objects.all.values('id','name')
  9. obj=list(obj)
  10. return Response(obj)
  11. else:
  12. print(1)
  13. obj = models.Article.objects.filter(pk=pk).first()
  14. obj=model_to_dict(obj)
  15. return Response(obj)

删除delete

  1. from api import models
  2. from django.forms.models import model_to_dict
  3. class DrfCategoryView(APIView):
  4. def delete(self,request,*args,**kwargs):
  5. """删除"""
  6. pk = kwargs.get('pk')
  7. models.Category.objects.filter(id=pk).delete()
  8. return Response('删除成功')

更新put

知识点

  1. request.data 可以进行序列化和解码
  2. 序列化和编码过程
  3. json格式字符串是双引号
  4. request.body: b'{"id":1,"name":"ALEX","AGE"}'
  5. 先进行解码
  6. json序列化
  7. json.loads(request.body.decode('utf-8'))
  8. request.data可以接受json &的数据

视图写法

  1. from api import models
  2. from django.forms.models import model_to_dict
  3. class DrfCategoryView(APIView):
  4. def put(self,request,*args,**kwargs):
  5. """更新"""
  6. pk = kwargs.get('pk')
  7. models.Category.objects.filter(id=pk).update(**request.data)
  8. return Response('更新成功')

增加post

  1. from api import models
  2. from django.forms.models import model_to_dict
  3. class DrfCategoryView(APIView):
  4. def post(self,request,*args,**kwargs):
  5. """增加一条分类信息"""
  6. #利用model对象之间点create 需要一条一条添加
  7. #因此需要打散字典变成关键字形式
  8. models.Category.objects.create(**request.data)
  9. return Response('成功')

序列化器serializer

  1. 查看正确的值
  2. is.vild()
  3. print(ser.validated_data)
  4. 多种情况使用多个serileiter进行区分 随机应变
  5. 是一个类
  6. #知识点
  7. 1.model 指定哪一个model
  8. 2.fields 表示需要序列化的字段,"__all__"全部字段
  9. 3.depth 向下查找一层。指对外键关系会继续遍历外键对象的全部属性。
  10. category=serializers.CharField(source='get_字段_display',required=False)
  11. source可以自动查询是不是可执行的 自动加括号()
  12. 展示特殊的数据(choicesFKM2M)可使用
  13. depth source,无需加括号,在源码内部会去判断是否可执行,如果可执行自动加括号。【fk/choice SerializerMethodField,定义钩子方法。【m2m

知识点

  1. data=request.data 指定关键字传参 把提交的数据增加到数据库中
  2. from rest_framework import serializers
  3. class NewCategorySerializer(serializers.ModelSerializer):
  4. class Meta:
  5. model = models.Category
  6. # fields = "__all__"
  7. fields = ['id','name']
  8. def get_date(self,obj):
  9. return obj.date.strftime('%Y-%m-%d %H:%M')
  10. def post(self,request,*args,**kwargs):
  11. ser = NewCategorySerializer(data=request.data)
  12. if ser.is_valid():
  13. ser.save()
  14. return Response(ser.data)
  15. return Response(ser.errors)

  1. def delete(self, request, *args, **kwargs):
  2. pk = kwargs.get("pk")
  3. if pk:
  4. obj=models.Article.objects.filter(pk=pk).delete()
  5. print(obj)
  6. return Response('删除成功')
  7. return Response('删除失败')

  1. def put(self,request,*args,**kwargs):
  2. pk = kwargs.get('pk')
  3. category_object = models.Category.objects.filter(id=pk).first()
  4. ser = NewCategorySerializer(instance=category_object,data=request.data)
  5. if ser.is_valid():
  6. ser.save()
  7. return Response(ser.data)
  8. return Response(ser.errors)

知识点

  1. 1.ser.data可以把quest类型变为字典
  2. ser.data
  3. 2.序列化对象 instance=对应的旧值
  4. 3.many=true允许查询多个表必须指定的值
  5. NewCategorySerializer(instance=queryset,many=True)

具体查询写法

  1. class NewCategoryView(APIView):
  2. def get(self,request,*args,**kwargs):
  3. pk = kwargs.get('pk')
  4. #多条数据查询
  5. if not pk:
  6. queryset = models.Category.objects.all()
  7. ser = NewCategorySerializer(instance=queryset,many=True)
  8. return Response(ser.data)
  9. else:
  10. #单条数据查询
  11. model_object = models.Category.objects.filter(id=pk).first()
  12. ser = NewCategorySerializer(instance=model_object, many=False)
  13. return Response(ser.data)

引用类似局部钩子

  1. 1.model 指定哪一个model
  2. 2.fields 表示需要序列化的字段,"__all__"全部字段
  3. 3.depth 向下查找一层。指对外键关系会继续遍历外键对象的全部属性。
  4. category=serializers.CharField(source='get_字段_display',required=False)
  5. source可以自动查询是不是可执行的 自动加括号()
  6. 展示特殊的数据(choicesFKM2M)可使用
  7. depth
  8. source,无需加括号,在源码内部会去判断是否可执行,如果可执行自动加括号。
  9. fk/choice SerializerMethodField,定义钩子方法。【m2m
  10. #datetime数据类型的显示
  11. 定义一个钩子
  12. date=serializers.SerializerMethodField()
  13. def get_date(self,obj):
  14. return obj.date.strftime(%Y-%m-%d %H:%M:%S) if obj.date else ""

获取外键对应的字段值

  1. from rest_framework import serializers
  2. from api import models
  3. 使用这个
  4. class ArticleSerializer(serializers.ModelSerializer):
  5. source='属性.跨表字段'
  6. #名字可以写成和model字段一样用于覆盖 字段名对应的值
  7. category=serializers.CharField(source='category.name',required=False)
  8. class Meta:
  9. model = models.Article
  10. fields = "__all__"
  11. #如果要写fields="__all__"
  12. #需要指定字段 是从获取字段名对应的值
  13. def get_x1(self,obj):
  14. return obj.category.name
  15. #查出来对象 可以点属性
  16. source可以自动查询是不是可执行的 自动加括号()

获取choice选择框对应值

  1. 获取choice选择框对应值
  2. from rest_framework import serializers
  3. from api import models
  4. 获取对应的列表的名称
  5. class ArticleSerializer(serializers.ModelSerializer):
  6. #第一种
  7. status_txt = serializers.CharField(source='get_status_display',required=False)
  8. #第二种
  9. x2 = serializers.SerializerMethodField()#类似一个钩子
  10. def get_x2(self,obj):
  11. return obj.get_status_display()
  12. #跨表
  13. class ArticleSerializer(serializers.ModelSerializer):
  14. x1 = serializers.SerializerMethodField()
  15. class Meta:
  16. model = models.Article
  17. # fields = "__all__"
  18. fields =
  19. ['id','title','summary','content','category','category_txt','x1','status','status_txt','x2']
  20. #如果放入fields
  21. #如果不写required=False或者read_onlye=False 会进行判断不为空
  22. def get_x1(self,obj)
  23. #obj当前表的对象
  24. #return 对象.字段属性.跨表字段
  25. return obj.category.name
  26. 多对多
  27. SerializerMethodField,定义钩子方法。【m2m
  28. class NewArticleSerializer(serializers.ModelSerializer): tag_info = serializers.SerializerMethodField() class Meta:
  29. model = models.Article
  30. fields = ['title','summary','tag_info']
  31. #钩子取出每一个字典
  32. def get_tag_info(self,obj):
  33. return [row for row in obj.tag.all().values('id','title')]
  34. class FormNewArticleSerializer(serializers.ModelSerializer): class Meta:
  35. model = models.Article
  36. fields = '__all__'

要想只更新一个字段

使用patch

  1. partial=True#允许部分更新
  2. partial=True
  3. def patch(self,request,*args,**kwargs):
  4. """局部"""
  5. pk = kwargs.get('pk')
  6. article_object = models.Article.objects.filter(id=pk).first()
  7. ser = serializer.ArticleSerializer(instance=article_object, data=request.data,partial=True)
  8. if ser.is_valid():
  9. ser.save()
  10. return Response(ser.data)
  11. return Response(ser.errors)

多对多关系

NewArticleSerializer写法

使用钩子

  1. class NewArticleSerializer(serializers.ModelSerializer):
  2. tag_info = serializers.SerializerMethodField()
  3. class Meta:
  4. model = models.Article
  5. fields = ['title','summary','tag_info']
  6. def get_tag_info(self,obj):
  7. return [row for row in obj.tag.all().values('id','title')]
  8. class FormNewArticleSerializer(serializers.ModelSerializer):
  9. class Meta:
  10. model = models.Article
  11. fields = '__all__'

视图类写法

  1. class NewArticleView(APIView):
  2. def get(self,request,*args,**kwargs):
  3. pk = kwargs.get('pk')
  4. if not pk:
  5. queryset = models.Article.objects.all()
  6. ser = serializer.NewArticleSerializer(instance=queryset,many=True)
  7. return Response(ser.data)
  8. article_object = models.Article.objects.filter(id=pk).first()
  9. ser = serializer.NewArticleSerializer(instance=article_object, many=False)
  10. return Response(ser.data)
  11. def post(self,request,*args,**kwargs):
  12. ser = serializer.FormNewArticleSerializer(data=request.data)
  13. if ser.is_valid():
  14. ser.save()
  15. return Response(ser.data)
  16. return Response(ser.errors)
  17. def put(self, request, *args, **kwargs):
  18. """全部更新"""
  19. pk = kwargs.get('pk')
  20. article_object = models.Article.objects.filter(id=pk).first()
  21. ser = serializer.FormNewArticleSerializer(instance=article_object, data=request.data) if ser.is_valid():
  22. ser.save()
  23. return Response(ser.data)
  24. return Response(ser.errors)
  25. def patch(self,request,*args,**kwargs):
  26. """局部"""
  27. pk = kwargs.get('pk')
  28. article_object = models.Article.objects.filter(id=pk).first()
  29. ser = serializer.FormNewArticleSerializer(instance=article_object,data=request.data,partial=True)
  30. if ser.is_valid():
  31. ser.save()
  32. return Response(ser.data)
  33. return Response(ser.errors)
  34. def delete(self,request,*args,**kwargs):
  35. pk = kwargs.get('pk')
  36. models.Article.objects.filter(id=pk).delete()
  37. return Response('删除成功')

分页

PageNumberPagination

用于固定页面显示

获取多条数据

知识点

  1. "count": 54,#每页显示多少条数据
  2. #下一页
  3. "next": "http://127.0.0.1:8000/drf/article/?page=2",
  4. #上一页
  5. "previous": null,

类的约束

  1. 必须写指定的功能
  2. # 约束子类中必须实现f1 class Base(object):
  3. def f1(self):
  4. raise NotImplementedError('asdfasdfasdfasdf')
  5. class Foo(Base):
  6. def f1(self):
  7. print(123)
  8. obj = Foo()
  9. obj.f1()

1.可以重写pagesize的类 pagenumber 继承

  1. 引用模块
  2. from rest_framework.pagination import PageNumberPagination#引用分页模块
  3. from rest_framework import serializers#引用序列化模块
  4. class pagesize(PageNumberPagination):
  5. page_size=1
  6. class PageArticleView(APIView):
  7. def get(self,request,*args,**kwargs):
  8. queryset=models.Article.objects.all()
  9. page_obj = pagesize()#实例化一个页面大小
  10. #进行分页
  11. result = page_obj.paginate_queryset(queryset, request, self)
  12. #把分页的数据写入序列化器
  13. ser = PageArticleerializer(instance=result, many=True)
  14. return page_obj.get_paginated_response(ser.data)

2.直接更改setting配置文件

  1. REST_FRAMEWORK = {
  2. "PAGE_SIZE":2
  3. }
  4. class PageArticleView(APIView):
  5. def get(self,request,*args,**kwargs):
  6. queryset=models.Article.objects.all()
  7. page_obj=PageNumberPagination()
  8. result=page_obj.paginate_queryset(queryset,request,self)
  9. ser=PageArticleerializer(instance=result,many=True)
  10. return Response(ser.data)

LimitOffsetPagination

  1. offset 0 limit 1
  2. offset开始数limit条数
  3. 用于滑动灵活运用
  4. 可以限制max_limit=2
  5. from rest_framework.pagination import PageNumberPagination
  6. from rest_framework.pagination import LimitOffsetPagination
  7. from rest_framework import serializers
  8. class PageArticleSerializer(serializers.ModelSerializer):
  9. class Meta:
  10. model = models.Article
  11. fields = "__all__"
  12. #重写父类
  13. class HulaLimitOffsetPagination(LimitOffsetPagination):
  14. max_limit = 2
  15. class PageArticleView(APIView):
  16. def get(self,request,*args,**kwargs):
  17. queryset = models.Article.objects.all()
  18. page_object = HulaLimitOffsetPagination()
  19. result = page_object.paginate_queryset(queryset, request, self)
  20. ser = PageArticleSerializer(instance=result, many=True)
  21. return Response(ser.data)

listapiview

url写法

  1. url(r'^page/view/article/$', views.PageViewArticleView.as_view()),

视图写法

  1. from rest_framework.generics import ListAPIView
  2. class PageViewArticleSerializer(serializers.ModelSerializer):
  3. class Meta:
  4. model = models.Article
  5. fields = "__all__"
  6. class PageViewArticleView(ListAPIView):
  7. queryset = models.Article.objects.all()
  8. #指定类
  9. serializer_class = PageViewArticleSerializer

setting配置

  1. #通过源码里面的配置进行分页的选择
  2. REST_FRAMEWORK = { "PAGE_SIZE":2,
  3. #分页的选择
  4. "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination"
  5. }

呼啦圈的设置

CMS系统格式

  1. 内容管理系统。CMS通常用作企业的数字信息管理系统,

功能的实现

  1. 1 增加文章(可以不写) #编写人员进行撰写 写入数据库
  2. 2 文章列表
  3. 3 文章详细
  4. 4 评论列表
  1. 1.没有变化的类型不需要创建一张表
  2. 2.数据量大的类似详细内容 需要另外开辟一张表,如果表中列(字段)太多 水平分表 进行一对一
  3. 3.图片路径存入数据库
  4. 4.自关联具有相同数据的表
  5. #不是必须的
  6. 可以不需要写外键提高查询效率

1.url路径

  1. urlpattent+=[]#为了区分增加的路径
  2. from django.conf.urls import url
  3. from api import views
  4. urlpatterns = [
  5. url(r'^Atricle/$', views.AtricleView.as_view()),
  6. ]
  7. urlpatterns+=[
  8. url(r'^Atricle/(?P<pk>\d+)/$', views.AtricleView.as_view()),
  9. url(r'^Comment/$', views.CommentView.as_view()),
  10. url(r'^Comment/(?P<pk>\d+)/$', views.CommentView.as_view()),
  11. ]

2.model 表结构

  1. from django.db import models
  2. class UserInfo(models.Model):
  3. """ 用户表 """
  4. username = models.CharField(verbose_name='用户名',max_length=32)
  5. password = models.CharField(verbose_name='密码',max_length=64)
  6. class Article(models.Model):
  7. """ 文章表 """
  8. category_choices = (
  9. (1,'咨询'),
  10. (2,'公司动态'),
  11. (3,'分享'),
  12. (4,'答疑'),
  13. (5,'其他'),
  14. )
  15. category = models.IntegerField(verbose_name='分类',choices=category_choices)
  16. title = models.CharField(verbose_name='标题',max_length=32)
  17. image = models.CharField(verbose_name='图片路径',max_length=128) # /media/upload/....
  18. summary = models.CharField(verbose_name='简介',max_length=255)
  19. comment_count = models.IntegerField(verbose_name='评论数',default=0)
  20. read_count = models.IntegerField(verbose_name='浏览数',default=0)
  21. author = models.ForeignKey(verbose_name='作者',to='UserInfo')
  22. date = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
  23. class ArticleDetail(models.Model):
  24. article = models.OneToOneField(verbose_name='文章表',to='Article')
  25. content = models.TextField(verbose_name='内容')
  26. class Comment(models.Model):
  27. """ 评论表 """
  28. article = models.ForeignKey(verbose_name='文章',to='Article')
  29. content = models.TextField(verbose_name='评论')
  30. user = models.ForeignKey(verbose_name='评论者',to='UserInfo')
  31. # parent = models.ForeignKey(verbose_name='回复',to='self', null=True,blank=True)

3.serlizer序列化器

知识点补充

  1. 1.#序列化器写法
  2. exclude=['字段']去除不进行校验
  3. 2.#序列化器内部的值
  4. ser是序列化器实例化的对象
  5. ser=序列化器(
  6. 1.instance=旧值(查询的值,数据库本类就有的)
  7. 2.data=要添加的值,提交的值(post请求,putpatch请求提交的值) )
  8. 3.查询的时候 需要指定many=True 查询多个值必须要指定
  9. ser.is_valid():
  10. '''
  11. 注意只打印存在字段的校验,
  12. 传入多的值不会进行打印和数据库的写入
  13. ser.errors是所有字段校验错误的信息
  14. '''
  15. print(ser.validated_data)#相当于modelform form校验的值
  16. ser.save()#存入数据库 括号里可以写值 由其他字段传入的
  17. #article=ser.save()#aricle是新增这条数据的对象

多个序列化器

接收前端发送的所有数据但只校验 序列化器含有的字段

ser=AtricleSeriALIZER(data=request.data)
ser_detail=ArtcleDetaili(data=request.data)
if ser.is_valid() and ser_detail.is_valid()
article=ser.save(author=1)
ser_detail.save(article=article)
#可以等于对象=对象
#也可等于id=id(内容回顾)
ser_detail.save(article.id=article.id)

```

4.view视图写法

post请求

(编写数据的人员去写)

知识点
  1. 1.多个serlizer序列化器进行保存
  2. 2.save里面可以添加参数
  3. 可以添加对应字段的id和对象类型的数据
  4. 没有办法直接添加外键对应的值 可以通过save(对应的值或者对象)
  5. 3.序列化的对象就是对应文章的对象
  6. 4.作者是登陆成功存入session的值 不需要手动传入
序列化器写法
  1. exclude=['author']#去除作者不进行校验
  2. #为了把字段写活request.session获取值进行匹配取得匹配的文章
  3. #查询对应文章对象不能直接post写死 因为不知道对应的文章
  4. class AtricleSerializers(serializers.ModelSerializer):
  5. class Meta:
  6. model = models.Article
  7. exclude = ['author', ]#外键字段不进行校验
  8. #request.session 登陆用户明进行匹配
  9. class AtricledetailSerializer(serializers.ModelSerializer):
  10. class Meta:
  11. model = models.ArticleDetail
  12. exclude = ['article', ]
  13. #外键字段不进行校验
  14. 2#文章对象或者文章值来确定 来确定添加对应的文章详细信息

view视图写法

两个序列化器进行校验

  1. def post(self, request, *args, **kwargs):
  2. ser = AtricleSerializers(data=request.data)
  3. serDetail = AtricledetailSerializer(data=request.data)
  4. print(request.data)
  5. if ser.is_valid() and serDetail.is_valid():
  6. # 因为作者id是根据登陆的id进行存储(例如session)
  7. print(ser.validated_data)
  8. atricle = ser.save(author_id=1)
  9. serDetail.save(article=atricle)
  10. return Response(f'{ser.data}{serDetail.data}')
  11. return Response('错误')

文章列表显示排序

先添加在显示

序列化写法
  1. class AtiricleliST(serializers.ModelSerializer):
  2. class Meta:
  3. model = models.Article
  4. fields = "__all__"
很多文章的获取get请求
  1. 多条数据
  2. 1.先进行实例化分页
  3. 2.把查询的数据进行分页,
  4. 3.放入序列化器里面进行处理显示
  5. def get(self, request, *args, **kwargs):
  6. pk=kwargs.get("pk")
  7. if not pk:
  8. Article_obj = models.Article.objects.all().order_by('-date')
  9. Page_obj = PageNumberPagination()
  10. Page = Page_obj.paginate_queryset(Article_obj, request, self)
  11. print(Page)
  12. ser = AtiricleliST(instance=Page, many=True)
  13. print(3)
  14. return Page_obj.get_paginated_response(ser.data)

文章筛选

前端的url
  1. 全部:http://127.0.0.1:8000/hg/article/
  2. 筛选:http://127.0.0.1:8000/hg/article/?category=2
视图
  1. #筛选文章的数据
  2. class ArticleView(APIView):
  3. """ 文章视图类 """
  4. def get(self,request,*args,**kwargs):
  5. """ 获取文章列表 """
  6. pk = kwargs.get('pk')
  7. if not pk:
  8. condition = {}#存储对应筛选
  9. category =
  10. #从前端url获取值
  11. request.query_params.get('category')
  12. if category:#如果由就进行过滤
  13. condition['category'] = category
  14. queryset =
  15. #**condition 字典打散然后进行筛选 分类为这个id的
  16. models.Article.objects.filter(**condition).order_by('-date')
  17. pager = PageNumberPagination()
  18. result = pager.paginate_queryset(queryset,request,self)
  19. ser = ArticleListSerializer(instance=result,many=True)
  20. return Response(ser.data)
  21. article_object = models.Article.objects.filter(id=pk).first()
  22. ser = PageArticleSerializer(instance=article_object,many=False)
  23. return Response(ser.data)

文章详细

  1. #去除对应的外键关联字段的验证article
  2. #只有文章创建了之后才能创建文章详情
  3. #author对应的是用户id值,例如session
  4. #因为文章详细不能直接创建需要通过文章对象关联创建
  5. class AtricledetailSerializer(serializers.ModelSerializer):
  6. class Meta:
  7. model = models.ArticleDetail
  8. exclude = ['article', ]
  9. class AtricleSerializers(serializers.ModelSerializer):
  10. class Meta:
  11. model = models.Article
  12. exclude = ['author', ]

查询一条数据的详细

view视图写法

  1. def get(self, request, *args, **kwargs):
  2. pk=kwargs.get("pk")
  3. if not pk:
  4. Article_obj = models.Article.objects.all().order_by('-date')
  5. Page_obj = PageNumberPagination()
  6. Page = Page_obj.paginate_queryset(Article_obj, request, self)
  7. print(Page)
  8. ser = AtiricleliST(instance=Page, many=True)
  9. print(3)
  10. return Page_obj.get_paginated_response(ser.data)
  11. #正文开始 else是一条 if是多条
  12. else:
  13. Article_obj=models.Article.objects.filter(pk=pk).first()
  14. #使用序列化处理一条数据
  15. ser=AtiricleDetail(instance=Article_obj,many=False)
  16. return Response(ser.data)
  17. ·································
  18. 文章详细 文章表反向小写表名查询详细表
  19. Article_obj=models.Article.objects.filter(pk=pk).first()
  20. 属性.小写表名.外键关联表属性
  21. print(Article_obj.articledetaili.content)

评论

1.访问get请求
  1. http://127.0.0.1:8000/hg/comment/?article=2
  2. request.query_params.get('article')
  3. #相当于request.GET。get 获取url的值
  4. query_params获取?后面值
  5. reqeust.data 相当于post
序列化器
  1. class MmentSerialiser(serializers.ModelSerializer):
  2. class Meta:
  3. model=models.Comment
  4. fields="__all__"
view视图
  1. 通过前端发送url进行筛选
  2. # http://127.0.0.1:8000/hg/comment/?article=2
  3. def get(self,request,*args,**kwargs):
  4. '''
  5. request.query_params.get()
  6. 相当于request.GET.get()
  7. '''
  8. coment=request.query_params.get('article')
  9. coment_obj=models.Comment.objects.filter(article_id=coment)
  10. show_coment=MmentSerialiser(instance=coment_obj,many=True)
  11. return Response(show_coment.data)
2.添加文章评论post请求
  1. #去掉对应外键字段硬不需要进行关联
  2. #request.session可以直接获取登陆的用户名
  3. class CommentSerialiser(serializers.ModelSerializer):
  4. class Meta:
  5. model=models.Comment
  6. exclude=['user']

锁定单个文章的评论增加

前端写法
  1. #返回数据的写法
  2. #第一种
  3. http://127.0.0.1:8000/hg/comment/
  4. {
  5. article:1,
  6. content:'xxx'
  7. }
  8. #第二种
  9. http://127.0.0.1:8000/hg/comment/?article=1
  10. {
  11. content:'xxx'
  12. }
view视图写法
  1. #文章由前端直接返回因为只有有了文章才能进行评论
  2. #通过前端数据进行返回
  3. def post(self,request,*args,**kwargs):
  4. ser=CommentSerialiser(data=request.data)
  5. if ser.is_valid():
  6. print(ser.validated_data)
  7. ser.save(user_id=1)
  8. return Response(ser.data)
  9. print(ser.errors)

过滤器

对查询出来的数据进行筛选可写可不写

  1. from rest_framework.filters import BaseFilterBackend
  2. 源码
  3. '''
  4. def filter_queryset(self, request, queryset, view):
  5. #继承了这个类必须写这个方法不然报错
  6. raise NotImplementedError(".filter_queryset() must be overridden.")
  7. '''
  8. view是当前视图self
  9. queryset是筛选之后的数据
  10. request 就是request
  11. def filter_queryset(self,request,queryset,view):
  12. pass

使用方法

  1. 对查询出来的数据进行筛选可写可不写
  2. #第一部分
  3. from rest_framework.filters import BaseFilterBackend
  4. #继承类
  5. class MyFilterBack(BaseFilterBackend):
  6. def filter_queryset(self,request,queryset,view):
  7. val = request.query_params.get('cagetory')
  8. return queryset.filter(category_id=val)
  9. #先实例化一个
  10. class IndexviewAPIview):
  11. def get(self,request,*arg,**kwargs):
  12. #就是查询一个表不理他
  13. queryset=models.News.objects.all()
  14. #实例化一个类对象
  15. obj=MyFilterBack()
  16. #传值顺序request,queryset,self
  17. result=obj.filter_queryset(request,queryset,self)
  18. return Response('...')

视图类

F查询

  1. def get(self,request,*args,**kwargs):
  2. # 1.获取单挑数据再做序列化
  3. result = super().get(request,*args,**kwargs)
  4. # 2.对浏览器进行自加1
  5. pk = kwargs.get('pk')
  6. models.Article.objects.filter(pk=pk).update(read_count=F('read_count')+1)
  7. # 3.对浏览器进行自加1
  8. # instance = self.get_object()
  9. # instance.read_count += 1
  10. # instance.save()
  11. return result

apiview

  1. 提供了公共方法
  2. request.data request.post的封装 json序列化
  3. dispatch()分发
  4. self封装了request属性
  5. self.request.method

源码剖析

  1. @classmethod
  2. def as_view(cls, **initkwargs):
  3. if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
  4. def force_evaluation():
  5. raise RuntimeError(
  6. 'Do not evaluate the `.queryset` attribute directly, '
  7. 'as the result will be cached and reused between requests. '
  8. 'Use `.all()` or call `.get_queryset()` instead.'
  9. )
  10. cls.queryset._fetch_all = force_evaluation
  11. #执行父类的as_view方法
  12. view = super().as_view(**initkwargs)
  13. #执行父类的super().as_view(**initkwargs)
  14. view.cls = cls
  15. view.initkwargs = initkwargs
  16. #闭包 csrf_exempt免除csrftoken的认证
  17. return csrf_exempt(view)
  18. --------------------------------------
  19. @classonlymethod
  20. def as_view(cls, **initkwargs):
  21. """
  22. Main entry point for a request-response process.
  23. """
  24. for key in initkwargs:
  25. if key in cls.http_method_names:
  26. raise TypeError("You tried to pass in the %s method name as a "
  27. "keyword argument to %s(). Don't do that."
  28. % (key, cls.__name__))
  29. if not hasattr(cls, key):
  30. raise TypeError("%s() received an invalid keyword %r. as_view "
  31. "only accepts arguments that are already "
  32. "attributes of the class." % (cls.__name__, key))
  33. def view(request, *args, **kwargs):
  34. self = cls(**initkwargs)
  35. if hasattr(self, 'get') and not hasattr(self, 'head'):
  36. self.head = self.get
  37. self.request = request
  38. self.args = args
  39. self.kwargs = kwargs
  40. #执行本类的self.dispatch
  41. return self.dispatch(request, *args,**kwargs)
  42. #执行view
  43. return view
  44. -------------apiviewdispatch--------
  45. def dispatch(self, request, *args, **kwargs):
  46. """
  47. `.dispatch()` is pretty much the same as Django's regular dispatch,
  48. but with extra hooks for startup, finalize, and exception handling.
  49. """
  50. self.args = args
  51. self.kwargs = kwargs
  52. #封装老值request
  53. request = self.initialize_request(request, *args, **kwargs)
  54. self.request = request
  55. self.headers = self.default_response_headers # deprecate?
  56. try:
  57. self.initial(request, *args, **kwargs)
  58. # Get the appropriate handler method
  59. if request.method.lower() in self.http_method_names:
  60. handler = getattr(self, request.method.lower(),
  61. self.http_method_not_allowed)
  62. else:
  63. handler = self.http_method_not_allowed
  64. response = handler(request, *args, **kwargs)
  65. except Exception as exc:
  66. response = self.handle_exception(exc)
  67. self.response = self.finalize_response(request, response, *args, **kwargs)
  68. return self.response

GenericAPIView

  1. #一 初识
  2. from rest_framework.generics import GenericAPIView
  3. GenericAPIview继承了APIview
  4. class NewView(GenericAPIview):
  5. querset=model.News.objects.all()
  6. def get(self,request,*arg,**kwargs):
  7. #self对应NewView的对象
  8. self.filter_queryset(self.queryset)
  9. 1.执行对应的filter_queryset方法
  10. 2.本类没有去寻找父类GenericAPIview
  11. '''
  12. def filter_queryset(self, queryset):
  13. for backend in list(self.filter_backends):
  14. queryset = backend().filter_queryset(self.request, queryset, self)
  15. return queryset
  16. '''#所以默认返回原来的queryset
  17. 3.寻找filter_backends
  18. '''
  19. filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
  20. filter_backends是空的
  21. '''

1. 本类重写filter_backends

  1. from rest_framework.generics import GenericAPIView
  2. #GenericAPIview继承了APIview
  3. class NewFiltrBackend(BaseFilterBackend):
  4. def filter_queryset(self,request,queryset,view):
  5. val = request.query_params.get('cagetory')
  6. return queryset.filter(category_id=val)
  7. class NewView(GenericAPIview):
  8. querset=model.News.objects.all()
  9. filter_backends=[NewFiltrBackend ,]
  10. def get(self,request,*arg,**kwargs):
  11. #self对应NewView的对象
  12. v=self.get_queryset()
  13. queryset=self.filter_queryset(v)
  14. 1.执行对应的filter_queryset方法
  15. 2.本类没有去寻找父类GenericAPIview
  16. '''
  17. 源码 继承类不写self.queryset会报错
  18. assert self.queryset is not None, (
  19. "'%s' should either include a `queryset` attribute, "
  20. "or override the `get_queryset()` method."
  21. % self.__class__.__name__
  22. )
  23. '''
  24. '''
  25. def filter_queryset(self, queryset):
  26. for backend in list(self.filter_backends):
  27. queryset = backend().filter_queryset(self.request, queryset, self)
  28. return queryset
  29. '''4.backend等于对应NewFiltrBackend类名() 实例化对象
  30. ·· 执行NewFiltrBackend里面的filter_queryset方法
  31. 3.寻找filter_backends,本类的filter_backends
  32. #filter_backends=[NewFiltrBackend ,]
  33. 5.queryset=self.filter_queryset(self.queryset)是筛选之后的结果
  34. #v=self.get_queryset()
  35. queryset=self.filter_queryset(v)
  36. 6.寻找对应get_queryset
  37. '''
  38. 源码
  39. queryset = self.queryset
  40. if isinstance(queryset, QuerySet):
  41. # Ensure queryset is re-evaluated on each request.
  42. queryset = queryset.all()
  43. return queryset
  44. '''#返回等于筛选之后的queryset
  45. #queryset=self.filter_queryset(queryset)
  46. #queryset=get_queryset()
  47. ·········self.get_serializer()···············
  48. class Newserializers(serializers.ModelSerializer):
  49. class Meta:
  50. model=models.News
  51. fields="__all__"
  52. class NewFiltrBackend(BaseFilterBackend):
  53. def filter_queryset(self,request,queryset,view):
  54. val = request.query_params.get('cagetory')
  55. return queryset.filter(category_id=val)
  56. class NewView(GenericAPIview):
  57. querset=model.News.objects.all()
  58. filter_backends=[NewFiltrBackend ,]
  59. def get(self,request,*arg,**kwargs):
  60. #self对应NewView的对象
  61. v=self.get_queryset()
  62. queryset=self.filter_queryset(v)
  63. self.get_serializer()#本类没有去父类找
  64. #代替了 ser=Newserializers(instance=queryset,many=True)
  65. #ser.data
  66. 1.寻找get_serializer()
  67. 2.
  68. '''
  69. 源码
  70. def get_serializer(self, *args, **kwargs):
  71. serializer_class = self.get_serializer_class()
  72. kwargs['context'] = self.get_serializer_context()
  73. return serializer_class(*args, **kwargs)
  74. '''
  75. 3.进行寻找get_serializer_class()本类没有去父类找
  76. #serializer_class = self.get_serializer_class()
  77. 4.
  78. '''
  79. def get_serializer_class(self):
  80. assert self.serializer_class is not None, (
  81. "'%s' should either include a `serializer_class` attribute, "
  82. "or override the `get_serializer_class()` method."
  83. % self.__class__.__name__
  84. )
  85. return self.serializer_class
  86. ''' #return self.serializer_class 返回serializer_class
  87. #get_serializer()=serializer_class
  88. 在本类定义seializer_class
  89. seializer_class=Newserializers
  90. 相当于 #ser=Newserializers(instance=queryset,many=True)
  91. #ser.data
  92. ser=self.get_serializer(instance=queryset,many=True)
  93. ser.data

分页
querset=model.News.objects.all()
pagination_class =PageNumberPagination
self.paginate_queryset(queryset)
'''
源码
self.paginate_queryset()

self._paginator = self.pagination_class()
需要定义
def paginator(self):
if not hasattr(self, '_paginator'):
if self.pagination_class is None:
self._paginator = None
else:
self._paginator = self.pagination_class()
return self._paginator

'''pagination_class()需要本地定义
pagination_class =PageNumberPagination
````

GenericAPIView源码总结

  1. 源码的剖析
  2. def get_queryset(self):
  3. """
  4. Get the list of items for this view.
  5. This must be an iterable, and may be a queryset.
  6. Defaults to using `self.queryset`.
  7. This method should always be used rather than accessing `self.queryset`
  8. directly, as `self.queryset` gets evaluated only once, and those results
  9. are cached for all subsequent requests.
  10. You may want to override this if you need to provide different
  11. querysets depending on the incoming request.
  12. (Eg. return a list of items that is specific to the user)
  13. """
  14. assert self.queryset is not None, (
  15. "'%s' should either include a `queryset` attribute, "
  16. "or override the `get_queryset()` method."
  17. % self.__class__.__name__
  18. )
  19. queryset = self.queryset
  20. if isinstance(queryset, QuerySet):
  21. # Ensure queryset is re-evaluated on each request.
  22. queryset = queryset.all()
  23. return queryset
  24. def get_object(self):
  25. """
  26. Returns the object the view is displaying.
  27. You may want to override this if you need to provide non-standard
  28. queryset lookups. Eg if objects are referenced using multiple
  29. keyword arguments in the url conf.
  30. """
  31. queryset = self.filter_queryset(self.get_queryset())
  32. # Perform the lookup filtering.
  33. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
  34. assert lookup_url_kwarg in self.kwargs, (
  35. 'Expected view %s to be called with a URL keyword argument '
  36. 'named "%s". Fix your URL conf, or set the `.lookup_field` '
  37. 'attribute on the view correctly.' %
  38. (self.__class__.__name__, lookup_url_kwarg)
  39. )
  40. filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
  41. obj = get_object_or_404(queryset, **filter_kwargs)
  42. # May raise a permission denied
  43. self.check_object_permissions(self.request, obj)
  44. return obj
  45. def get_serializer(self, *args, **kwargs):
  46. """
  47. Return the serializer instance that should be used for validating and
  48. deserializing input, and for serializing output.
  49. """
  50. serializer_class = self.get_serializer_class()
  51. kwargs['context'] = self.get_serializer_context()
  52. return serializer_class(*args, **kwargs)
  53. def get_serializer_class(self):
  54. """
  55. Return the class to use for the serializer.
  56. Defaults to using `self.serializer_class`.
  57. You may want to override this if you need to provide different
  58. serializations depending on the incoming request.
  59. (Eg. admins get full serialization, others get basic serialization)
  60. """
  61. assert self.serializer_class is not None, (
  62. "'%s' should either include a `serializer_class` attribute, "
  63. "or override the `get_serializer_class()` method."
  64. % self.__class__.__name__
  65. )
  66. return self.serializer_class
  67. def get_serializer_context(self):
  68. """
  69. Extra context provided to the serializer class.
  70. """
  71. return {
  72. 'request': self.request,
  73. 'format': self.format_kwarg,
  74. 'view': self
  75. }
  76. def filter_queryset(self, queryset):
  77. """
  78. Given a queryset, filter it with whichever filter backend is in use.
  79. You are unlikely to want to override this method, although you may need
  80. to call it either from a list view, or from a custom `get_object`
  81. method if you want to apply the configured filtering backend to the
  82. default queryset.
  83. """
  84. for backend in list(self.filter_backends):
  85. queryset = backend().filter_queryset(self.request, queryset, self)
  86. return queryset
源码解释
  1. from rest_framework.generics import GenericAPIView
  2. from rest_framework.filters import BaseFilterBackend
  3. from rest_framework import serializers
  4. GenericAPIview继承了APIview
  5. class Newserializers(serializers.ModelSerializer):
  6. class Meta:
  7. model=models.News
  8. fields="__all__"
  9. class NewFiltrBackend(BaseFilterBackend):
  10. def filter_queryset(self,request,queryset,view):
  11. val = request.query_params.get('cagetory')
  12. return queryset.filter(category_id=val)
  13. class NewView(GenericAPIview):
  14. querset=model.News.objects.all()
  15. filter_backends=[NewFiltrBackend ,]
  16. seializer_class=Newserializers
  17. def get(self,request,*arg,**kwargs):
  18. #self对应NewView的对象
  19. v=self.get_queryset()
  20. queryset=self.filter_queryset(v)
  21. self.get_serializer(instance==queryset,many=True)
  22. retutn Response(ser.data)
  23. '''
  24. 1.querset=model.News.objects.all()
  25. 2.filter_backends=[NewFiltrBackend ,]
  26. 3.seializer_class=Newserializers
  27. 4.pagination_class =PageNumberPagination
  28. 1.查询
  29. self.get_queryset()#等于querset=model.News.objects.all()
  30. 2.序列化
  31. self.get_serializer()等于seializer_class=Newserializers()
  32. 3.筛选
  33. self.filter_queryset()
  34. 等于filter_backends=[NewFiltrBackend ,]
  35. 内部有一个for循环列表 同等与NewFiltrBackend()
  36. 4.分页
  37. self.paginate_queryset(queryset)
  38. 等于page_obj=PageNumberPagination()
  39. '''

基于GenericAPIView

listapiview查看

基于GenericAPIView

模拟get请求

  1. 1.queryset
  2. 2.分页
  3. #settings的配置
  4. paginator.paginate_queryset(queryset, self.request, view=self)
  5. "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
  6. "PAGE_SIZE":2,
  7. 3.序列化
  8. 4.返回序列化数据

源码剖析

  1. #源码
  2. def get(self, request, *args, **kwargs):
  3. return self.list(request, *args, **kwargs)
  4. 1.执行list
  5. def list(self, request, *args, **kwargs):
  6. queryset = self.filter_queryset(self.get_queryset())
  7. #self.get_queryset()执行自定的
  8. #queryset=model.News.objects.all()
  9. #self.filter_queryset()筛选执行
  10. #filter_backends=[NewFiltrBackend ,]
  11. #执行对应本类的filter_queryset
  12. 2. page = self.paginate_queryset(queryset)
  13. #分页
  14. #执行 pagination_class =PageNumberPagination
  15. if page is not None:
  16. 3.serializer = self.get_serializer(page, many=True)
  17. #序列化 执行seializer_class=Newserializers
  18. return self.get_paginated_response(serializer.data)
  19. serializer = self.get_serializer(queryset, many=True)
  20. return Response(serializer.data)
  21. #最后返回序列化的数据

RetrieveAPIView单条查看

模拟get请求

执行流程

  1. 1. #对应获得对象 自己要定义单条数据 queryset
  2. 2. #序列化
  3. 3. #返回数据

源码剖析

  1. class RetrieveAPIView(mixins.RetrieveModelMixin,
  2. GenericAPIView):
  3. #从左往右继承
  4. def get(self, request, *args, **kwargs):
  5. return self.retrieve(request, *args, **kwargs)
  6. #去找retrieve这个方法
  7. class RetrieveModelMixin:
  8. """
  9. Retrieve a model instance.
  10. """
  11. def retrieve(self, request, *args, **kwargs):
  12. #对应获得对象
  13. instance = self.get_object()
  14. #序列化
  15. serializer = self.get_serializer(instance)
  16. #返回数据
  17. return Response(serializer.data)
  18. 执行
  19. def get_object(self):
  20. """
  21. Returns the object the view is displaying.
  22. You may want to override this if you need to provide non-standard
  23. queryset lookups. Eg if objects are referenced using multiple
  24. keyword arguments in the url conf.
  25. """
  26. queryset = self.filter_queryset(self.get_queryset())
  27. # Perform the lookup filtering.
  28. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
  29. assert lookup_url_kwarg in self.kwargs, (
  30. 'Expected view %s to be called with a URL keyword argument '
  31. 'named "%s". Fix your URL conf, or set the `.lookup_field` '
  32. 'attribute on the view correctly.' %
  33. (self.__class__.__name__, lookup_url_kwarg)
  34. )
  35. return obj

基于GenericAPIView

createapiview创建

基于GenericAPIView

封装了post请求

执行流程

  1. 1.序列化
  2. 2.序列化验证
  3. 3.保存数据

源码剖析

  1. def post(self, request, *args, **kwargs):
  2. return self.create(request, *args, **kwargs)
  3. 1.执行create
  4. def create(self, request, *args, **kwargs):
  5. serializer = self.get_serializer(data=request.data)
  6. #序列化
  7. serializer.is_valid(raise_exception=True)
  8. #序列化验证
  9. self.perform_create(serializer)
  10. '''
  11. 保存数据
  12. def perform_create(self, serializer):
  13. serializer.save()
  14. '''
  15. headers = self.get_success_headers(serializer.data)
  16. return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

示例使用

  1. #第一种写法重写create书写 多条序列化器
  2. def create(self, request, *args, **kwargs):
  3. article = articleseralizer(data=request.data)
  4. articleDetail = atricleDetaliser(data=request.data)
  5. if article.is_valid() and articleDetail.is_valid():
  6. article_obj = article.save(author=request.user)
  7. print(">>>>>>>>>", request.user, type(request.user))
  8. articleDetail.save(article=article_obj)
  9. return Response('修改成功')
  10. else:
  11. return Response(f"{article.errors},{articleDetail.errors}")
  12. #第二种方式
  13. 重写序列化器分发
  14. def get_serializer_class(self):
  15. self.request.method=="POST":
  16. return 对应序列化器
  17. self.request.method=="GET":
  18. return 对应序列化器
  19. def perform_create(self,serializer):
  20. Aritlel=serializer.save(author)
  21. serializer_second=AricleSerializer(data=request.data)
  22. serializer.save(aritle=Aritlel)
  23. 字段对象=对象

UpdateAPIView全局局部

封装了局部更新和全局更新

基于GenericAPIView

执行流程

  1. 1.获取更新那条数据的对象
  2. 2.序列化
  3. 2.序列化校验
  4. 3.校验成功更新

源码剖析

  1. def put(self, request, *args, **kwargs):
  2. return self.update(request, *args, **kwargs)
  3. '''
  4. def update(self, request, *args, **kwargs):
  5. partial = kwargs.pop('partial', False)
  6. instance = self.get_object()
  7. '''
  8. #执行queryset查询处理的model对象
  9. #相当于
  10. #queryset=model.表名.object.filter(pk=pk).frist()
  11. '''
  12. serializer = self.get_serializer(instance, data=request.data, partial=partial)默认不为Ture
  13. #执行对应的序列化
  14. serializer.is_valid(raise_exception=True)
  15. #序列化验证
  16. self.perform_update(serializer)
  17. '''
  18. # def perform_update(self, serializer):
  19. #serializer.save()
  20. def patch(self, request, *args, **kwargs):
  21. return self.partial_update(request, *args, **kwargs)
  22. '''
  23. def partial_update(self, request, *args, **kwargs):
  24. kwargs['partial'] = True
  25. return self.update(request, *args, **kwargs)
  26. '''
  27. 执行
  28. '''
  29. def update(self, request, *args, **kwargs):
  30. partial = kwargs.pop('partial', False)
  31. instance = self.get_object()
  32. '''
  33. #执行queryset查询处理的model对象
  34. #相当于
  35. #queryset=model.表名.object.filter(pk=pk).frist()
  36. '''
  37. serializer = self.get_serializer(instance, data=request.data, partial=partial)
  38. kwargs['partial'] = True 局部更新
  39. #执行对应的序列化
  40. serializer.is_valid(raise_exception=True)
  41. #序列化验证
  42. self.perform_update(serializer)
  43. '''
  44. # def perform_update(self, serializer):
  45. #serializer.save()

删除DestroyAPIView

执行流程

  1. 1.传入对象
  2. 2.执行def perform_destroy(self, instance):
  3. 3.删除

源码剖析

  1. def delete(self, request, *args, **kwargs):
  2. return self.destroy(request, *args, **kwargs)
  3. def destroy(self, request, *args, **kwargs):
  4. instance = self.get_object()
  5. #c传入对象删除
  6. self.perform_destroy(instance)
  7. return Response(status=status.HTTP_204_NO_CONTENT)
  8. def perform_destroy(self, instance):
  9. instance.delete()#删除

Viewset视图类

是APIview视图类的继承对象

  1. createapiview
  2. UpdateAPIview。。。。等等

使用方法

  1. 1.直接继承即可
  2. 2.因为没有封装对应get post等请求方法 一点点去找父类的方法
  3. 3.GenericViewSet(ViewSetMixin)它继承的ViewSetMixin
  4. 4.重写了asview()需要传参
  5. 5.使用两个类进行id和没有id的区分
  6. url(r'^article/$',article.AtricleView.as_view({"get":"list"}))
  7. url(r'^article/(?P<pk>\d+)/$',article.AtricleView.as_view({"get":"retrieve"}))

知识点

  1. from rest_framework.viewsets import GenericVIewSet
  2. class GenericViewSet(ViewSetMixin,generics.GenericAPIView
  3. ):
  4. 默认继承GenericAPIView
  5. def get_serializer_class(self):
  6. pk = self.kwargs.get('pk')
  7. if pk:
  8. return ArticleDetailSerializer
  9. return ArticleSerializer

ListModelMixin添加

源码

  1. def list(self, request, *args, **kwargs):
  2. queryset = self.filter_queryset(self.get_queryset())
  3. page = self.paginate_queryset(queryset)
  4. if page is not None:
  5. serializer = self.get_serializer(page, many=True)
  6. return self.get_paginated_response(serializer.data)
  7. serializer = self.get_serializer(queryset, many=True)
  8. return Response(serializer.data)

RetrieveModelMixin单条查询

源码

  1. def retrieve(self, request, *args, **kwargs):
  2. instance = self.get_object()
  3. serializer = self.get_serializer(instance)
  4. return Response(serializer.data)

UpdateModelMixin更新

源码

  1. def update(self, request, *args, **kwargs):
  2. partial = kwargs.pop('partial', False)
  3. instance = self.get_object()
  4. serializer = self.get_serializer(instance, data=request.data, partial=partial)
  5. serializer.is_valid(raise_exception=True)
  6. self.perform_update(serializer)
  7. if getattr(instance, '_prefetched_objects_cache', None):
  8. # If 'prefetch_related' has been applied to a queryset, we need to
  9. # forcibly invalidate the prefetch cache on the instance.
  10. instance._prefetched_objects_cache = {}
  11. return Response(serializer.data)
  12. def perform_update(self, serializer):
  13. serializer.save()
  14. #
  15. def partial_update(self, request, *args, **kwargs):
  16. kwargs['partial'] = True
  17. return self.update(request, *args, **kwargs)
  18. class

DestroyModelMixin:

删除

源码

  1. class DestroyModelMixin:
  2. """
  3. Destroy a model instance.
  4. """
  5. def destroy(self, request, *args, **kwargs):
  6. instance = self.get_object()
  7. self.perform_destroy(instance)
  8. return Response(status=status.HTTP_204_NO_CONTENT)
  9. def perform_destroy(self, instance):
  10. instance.delete()

版本

setting配置

  1. default_version = api_settings.DEFAULT_VERSION
  2. #默认版本
  3. allowed_versions = api_settings.ALLOWED_VERSIONS
  4. #指定版本
  5. version_param = api_settings.VERSION_PARAM
  6. #url版本传输关键字
  7. #指定版本类类
  8. "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",

知识点

  1. dispath 老的request 封装了很多功能
  2. request.version#版本
  3. scheme#版本对象
  4. #执行返回一个版本元组 第一个是版本第二个是版本对象
  5. def determine_version(self, request, *args, **kwargs):
  6. """
  7. If versioning is being used, then determine any API version for the
  8. incoming request. Returns a two-tuple of (version, versioning_scheme)
  9. """
  10. if self.versioning_class is None:
  11. return (None, None)
  12. scheme = self.versioning_class()
  13. return (scheme.determine_version(request, *args, **kwargs), scheme)
  14. request.version, request.versioning_scheme = version, scheme

源码执行流程

  1. class APIView(View):
  2. versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
  3. def dispatch(self, request, *args, **kwargs):
  4. # ###################### 第一步 ###########################
  5. """
  6. request,是django的request,它的内部有:request.GET/request.POST/request.method
  7. args,kwargs是在路由中匹配到的参数,如:
  8. url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
  9. http://www.xxx.com/order/1/v2/
  10. """
  11. self.args = args
  12. self.kwargs = kwargs
  13. """
  14. request = 生成了一个新的request对象,此对象的内部封装了一些值。
  15. request = Request(request)
  16. - 内部封装了 _request = 老的request
  17. """
  18. request = self.initialize_request(request, *args, **kwargs)
  19. self.request = request
  20. self.headers = self.default_response_headers # deprecate?
  21. try:
  22. # ###################### 第二步 ###########################
  23. self.initial(request, *args, **kwargs)
  24. 执行视图函数。。
  25. def initial(self, request, *args, **kwargs):
  26. # ############### 2.1 处理drf的版本 ##############
  27. version, scheme = self.determine_version(request, *args, **kwargs)
  28. request.version, request.versioning_scheme = version, scheme
  29. ...
  30. def determine_version(self, request, *args, **kwargs):
  31. if self.versioning_class is None:
  32. return (None, None)
  33. #是版本类的实例化对象
  34. scheme = self.versioning_class()
  35. # obj = XXXXXXXXXXXX()
  36. return (scheme.determine_version(request, *args, **kwargs), scheme)
  37. class OrderView(APIView):
  38. versioning_class = URLPathVersioning
  39. def get(self,request,*args,**kwargs):
  40. print(request.version)
  41. print(request.versioning_scheme)
  42. return Response('...')
  43. def post(self,request,*args,**kwargs):
  44. return Response('post')

1.局部配置

视图写法

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from rest_framework.request import Request
  4. from rest_framework.versioning import URLPathVersioning
  5. class OrderView(APIView):
  6. versioning_class = URLPathVersioning
  7. def get(self,request,*args,**kwargs):
  8. print(request.version)
  9. print(request.versioning_scheme)
  10. return Response('...')
  11. def post(self,request,*args,**kwargs):
  12. return Response('post')

setting配置

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

2.全局配置

不用手动一个个加全部都配置上

url

  1. url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
  2. url(r'^(?P<version>\w+)/users/$', users_list, name='users-list'),

settings配置

  1. REST_FRAMEWORK = {
  2. 指定版本类 必须要写要些路径 "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
  3. #限制版本范围
  4. "ALLOWED_VERSIONS":['v1','v2'],
  5. #指定url有名分组的关键字
  6. 'VERSION_PARAM':'version'
  7. }

认证

  1. 自定义认证token
  2. 把数据库的user拿出来比较
  3. 如果想使用**request.data 就要把他变为字典 所以前端要返回json数据类型
  4. 源码写法
  5. #配置
  6. authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

局部配置

  1. 和登陆配合使用
  2. import uuid
  3. from django.shortcuts import render
  4. from django.views import View
  5. from django.views.decorators.csrf import csrf_exempt
  6. from django.utils.decorators import method_decorator
  7. from rest_framework.versioning import URLPathVersioning
  8. from rest_framework.views import APIView
  9. from rest_framework.response import Response
  10. class Loginview(APIView):
  11. versioning_class = None
  12. #认证写法
  13. authentication_classes = [Myauthentication, ]
  14. def post(self,request,*args,**kwargs):
  15. user_object = models.UserInfo.objects.filter(**request.data).first()
  16. if not user_object:
  17. return Response('登录失败')
  18. random_string = str(uuid.uuid4())
  19. user_object.token = random_string
  20. user_object.save()
  21. return Response(random_string)
  22. class MyAuthentication:
  23. def authenticate(self, request):
  24. """
  25. Authenticate the request and return a two-tuple of (user, token).
  26. """
  27. token = request.query_params.get('token')
  28. user_object = models.UserInfo.objects.filter(token=token).first()
  29. if user_object:
  30. return (user_object,token)
  31. return (None,None)
  32. class OrderView(APIView):
  33. authentication_classes = [MyAuthentication, ]
  34. def get(self,request,*args,**kwargs):
  35. print(request.user)
  36. print(request.auth)
  37. return Response('order')
  38. class UserView(APIView):
  39. authentication_classes = [MyAuthentication,]
  40. def get(self,request,*args,**kwargs):
  41. print(request.user)
  42. print(request.auth)
  43. return Response('user')
  44. ···············手写认证类····························
  45. class Myauthentication:
  46. # 认证
  47. # versioning_class = None
  48. #手写认证
  49. def authenticate(self, request):
  50. token = request.query_params.get('token')
  51. print(token)
  52. user_object = models.UserInfo.objects.filter(token=token).first()
  53. print(user_object)
  54. if user_object:
  55. print(1)
  56. #必须返回一个元组的形式
  57. #返回对应的user_object和token值
  58. return (user_object, token)
  59. else:
  60. print(2)
  61. return (None, None)
  62. ----------------------
  63. 为什么要返回元组
  64. ----------------------
  65. #为什么要返回元组
  66. def _authenticate(self):
  67. """
  68. Attempt to authenticate the request using each authentication instance
  69. in turn.
  70. """
  71. for authenticator in self.authenticators:
  72. try:
  73. user_auth_tuple =
  74. #到这返回为什么可以执行对应的方法
  75. authenticator.authenticate(self)
  76. except exceptions.APIException:
  77. self._not_authenticated()
  78. raise
  79. if user_auth_tuple is not None:
  80. #把查询出来的元组
  81. self._authenticator = authenticator
  82. #给user和auth进行赋值
  83. self.user, self.auth = user_auth_tuple#必须返回一个元组的形式
  84. return#结束函数
  85. self._not_authenticated()
  86. def _not_authenticated(self):
  87. """
  88. Set authenticator, user & authtoken representing an unauthenticated request.
  89. Defaults are None, AnonymousUser & None.
  90. """
  91. self._authenticator = None
  92. if api_settings.UNAUTHENTICATED_USER:
  93. #user 没有设置返回none
  94. self.user =
  95. #匿名用户
  96. api_settings.UNAUTHENTICATED_USER()
  97. else:
  98. self.user = None
  99. if api_settings.UNAUTHENTICATED_TOKEN:
  100. self.auth =
  101. #对应author没有设置返回none
  102. api_settings.UNAUTHENTICATED_TOKEN()
  103. else:
  104. self.auth = None

全局配置

  1. DEFAULT_AUTHENTICATION_CLASSES=['写一个认证的类手写的']
  2. class Myauthentication:
  3. # 认证
  4. # versioning_class = None
  5. #手写认证
  6. def authenticate(self, request):
  7. token = request.query_params.get('token')
  8. print(token)
  9. user_object = models.UserInfo.objects.filter(token=token).first()
  10. print(user_object)
  11. if user_object:
  12. print(1)
  13. #必须返回一个元组的形式
  14. #返回对应的user_object和token值
  15. return (user_object, token)
  16. else:
  17. print(2)
  18. return (None, None)
  19. '''
  20. # raise Exception(), 不在继续往下执行,直接返回给用户。
  21. # return None ,本次认证完成,执行下一个认证
  22. # return ('x',"x"),认证成功,不需要再继续执行其他认证了,继续往后权限、节流、视图函数
  23. '''

view视图写法

  1. class LoginView(APIView):
  2. authentication_classes = []
  3. def post(self,request,*args,**kwargs):
  4. user_object = models.UserInfo.objects.filter(**request.data).first()
  5. if not user_object:
  6. return Response('登录失败')
  7. random_string = str(uuid.uuid4())
  8. user_object.token = random_string
  9. user_object.save()
  10. return Response(random_string)
  11. class OrderView(APIView):
  12. # authentication_classes = [TokenAuthentication, ]
  13. def get(self,request,*args,**kwargs):
  14. print(request.user)
  15. print(request.auth)
  16. if request.user:
  17. return Response('order')
  18. return Response('滚')
  19. class UserView(APIView):
  20. 同上

源码执行流程

  1. '''
  2. 当请求发过来的实话会先执行 apiview里面的dispath方法
  3. 1.执行认证的dispatch的方法
  4. 2.dispatch方法会执行initialize_request方法封装旧的request对象
  5. 3.在封装的过程中会执行
  6. get_authenticators(self): 并实例化列表中的每一个认证类
  7. 如果自己写的类有对应的认证类 会把认证类的实例化对象封装到新的request当中
  8. 继续执行initial
  9. 会执行认证里面的perform_authentication 执行request.user
  10. 会执行循环每一个对象执行对应的authenticate方法
  11. 会有三种返回值
  12. # raise Exception(), 不在继续往下执行,直接返回给用户。
  13. # return None ,本次认证完成,执行下一个认证
  14. # return ('x',"x"),认证成功,不需要再继续执行其他认证了,继续往后权限、节流、视图函数
  15. 里面会执行四件事
  16. 版本
  17. 认证
  18. 权限
  19. 节流
  20. '''
  21. def dispatch(self, request, *args, **kwargs):
  22. """
  23. `.dispatch()` is pretty much the same as Django's regular dispatch,
  24. but with extra hooks for startup, finalize, and exception handling.
  25. """
  26. self.args = args
  27. self.kwargs = kwargs
  28. #封装旧的request
  29. request = self.initialize_request(request, *args, **kwargs)
  30. self.request = request
  31. self.headers = self.default_response_headers # deprecate?
  32. 循环自定义的认证
  33. #request封装旧的request执行initialize_request
  34. def initialize_request(self, request, *args, **kwargs):
  35. """
  36. Returns the initial request object.
  37. """
  38. parser_context = self.get_parser_context(request)
  39. return Request(
  40. request,
  41. parsers=self.get_parsers(),
  42. authenticators=self.get_authenticators(),
  43. negotiator=self.get_content_negotiator(),
  44. parser_context=parser_context
  45. )
  46. def get_authenticators(self):
  47. """
  48. Instantiates and returns the list of authenticators that this view can use.
  49. """
  50. return [auth() for auth in self.authentication_classes]
  51. def initial(self, request, *args, **kwargs):
  52. """
  53. Runs anything that needs to occur prior to calling the method handler.
  54. """
  55. self.format_kwarg = self.get_format_suffix(**kwargs)
  56. # Perform content negotiation and store the accepted info on the request
  57. neg = self.perform_content_negotiation(request)
  58. request.accepted_renderer, request.accepted_media_type = neg
  59. # Determine the API version, if versioning is in use.
  60. version, scheme = self.determine_version(request, *args, **kwargs)
  61. request.version, request.versioning_scheme = version, scheme
  62. # Ensure that the incoming request is permitted
  63. self.perform_authentication(request)
  64. self.check_permissions(request)
  65. self.check_throttles(request)
  66. #执行完四件事在执行视图

权限

  1. message=消息 自定义错误消息
  2. 可以自定义错误信息
  3. '''
  4. for permission in self.get_permissions():
  5. if not permission.has_permission(request, self):
  6. self.permission_denied(
  7. request, message=getattr(permission, 'message', None)
  8. )
  9. '''
  10. 本质上自定义和
  11. return Flase
  12. 单条验证
  13. 验证两次
  14. 不写url_kwarg默认封装识别pk关键字

重写错误信息的两种方式

第一种

  1. message={"code":"恭喜你报错了"}

第二种

  1. from rest_framework.permissions import BasePermission
  2. from rest_framework import exceptions
  3. class MyPermission(BasePermission):
  4. #第一种
  5. message = {'code': 10001, 'error': '你没权限'}
  6. def has_permission(self, request, view):
  7. #request.user执行认证
  8. if request.user:
  9. return True
  10. #自定义错误信息
  11. raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'})
  12. return False
  13. def has_object_permission(self, request, view, obj):
  14. """
  15. Return `True` if permission is granted, `False` otherwise.
  16. """
  17. return False
  18. #对应源码
  19. 相当于重写了错误信息
  20. #执行顺序
  21. dispatch---》intital--》check_permissions--》permission_denied
  22. def permission_denied(self, request, message=None):
  23. """
  24. If request is not permitted, determine what kind of exception to raise.
  25. """
  26. if request.authenticators and not request.successful_authenticator:
  27. raise exceptions.NotAuthenticated()
  28. raise
  29. #等于message 或者自定义错误函数
  30. #raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'})
  31. exceptions.PermissionDenied(detail=message)
  32. ················源码··················
  33. def check_permissions(self, request):
  34. for permission in self.get_permissions():
  35. if not permission.has_permission(request, self):
  36. self.permission_denied(
  37. request, message=getattr(permission, 'message', None)
  38. )

源码剖析

执行流程
  1. apiview
  2. ---
  3. dispatch
  4. ---
  5. initial
  6. ---
  7. 执行权限判断
  8. 如果自己写了权限类 会先循环权限类并实例化存在列表当中
  9. 然后循环列表对象,如果权限判断返回不为Ture机会进行主动抛出异常
  10. 可以自定义错误信息
具体代码
  1. class APIView(View):
  2. permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
  3. def dispatch(self, request, *args, **kwargs):
  4. 封装request对象
  5. self.initial(request, *args, **kwargs)
  6. 通过反射执行视图中的方法
  7. def initial(self, request, *args, **kwargs):
  8. 版本的处理
  9. # 认证
  10. self.perform_authentication(request)
  11. # 权限判断
  12. self.check_permissions(request)
  13. self.check_throttles(request)
  14. #执行认证
  15. def perform_authentication(self, request):
  16. request.user
  17. def check_permissions(self, request):
  18. # [对象,对象,]
  19. self.执行
  20. '''
  21. def get_permissions(self):
  22. return [permission() for permission in self.permission_classes]
  23. '''
  24. for permission in self.get_permissions():
  25. if not permission.has_permission(request, self):
  26. self.permission_denied(request, message=getattr(permission, 'message', None))
  27. def permission_denied(self, request, message=None):
  28. if request.authenticators and not request.successful_authenticator:
  29. raise exceptions.NotAuthenticated()
  30. raise exceptions.PermissionDenied(detail=message)
  31. #
  32. class UserView(APIView):
  33. permission_classes = [MyPermission, ]
  34. def get(self,request,*args**kwargs):
  35. return Response('user')

使用

  1. class MyPermission(BasePermission):
  2. message = {'code': 10001, 'error': '你没权限'}
  3. def has_permission(self, request, view):
  4. #request.user执行认证
  5. if request.user:
  6. return True
  7. raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'})
  8. return False
  9. def has_object_permission(self, request, view, obj):
  10. """
  11. Return `True` if permission is granted, `False` otherwise.
  12. """
  13. return False
  14. class UserView(APIView):
  15. 先执行上面的数据
  16. permission_classes = [MyPermission, ]
  17. #再执行
  18. def get(self,request,*args**kwargs):
  19. return Response('user')

源码流程

``python def dispatch(self, request, *args, **kwargs): """.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?

  1. try:
  2. #走这
  3. self.initial(request, *args, **kwargs)

`````````````````def initial``````````````````````````

  1. def initial(self, request, *args, **kwargs):
  2. """
  3. Runs anything that needs to occur prior to calling the method handler.
  4. """
  5. self.format_kwarg = self.get_format_suffix(**kwargs)
  6. # Perform content negotiation and store the accepted info on the request
  7. neg = self.perform_content_negotiation(request)
  8. request.accepted_renderer, request.accepted_media_type = neg
  9. # Determine the API version, if versioning is in use.
  10. version, scheme =
  11. '''
  12. 第三步
  13. '''
  14. self.determine_version(request, *args, **kwargs)
  15. request.version, request.versioning_scheme = version, scheme
  16. # Ensure that the incoming request is permitted
  17. self.perform_authentication(request)
  18. self.check_permissions(request)
  19. self.check_throttles(request)

第二步

def check_permissions(self, request):
# [对象,对象,]
self.执行
'''
def get_permissions(self):
return [permission() for permission in self.permission_classes]
'''
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(request, message=getattr(permission, 'message', None))
def permission_denied(self, request, message=None):
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message)
```

第三步

  1. def determine_version(self, request, *args, **kwargs):
  2. if self.versioning_class is None:
  3. return (None, None)
  4. scheme = self.versioning_class()
  5. return (scheme.determine_version(request, *args, **kwargs), scheme)

单挑数据的验证

单挑数据

  1. def has_object_permission(self, request, view, obj):
  2. """
  3. Return `True` if permission is granted, `False` otherwise.
  4. """
  5. return False
  6. #在执行RetrieveAPIView 会执行单挑数据的验证
  7. def get_object(self):
  8. queryset = self.filter_queryset(self.get_queryset())
  9. # Perform the lookup filtering.
  10. #不写url_kwarg默认封装识别pk关键字
  11. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
  12. assert lookup_url_kwarg in self.kwargs, (
  13. 'Expected view %s to be called with a URL keyword argument '
  14. 'named "%s". Fix your URL conf, or set the `.lookup_field` '
  15. 'attribute on the view correctly.' %
  16. (self.__class__.__name__, lookup_url_kwarg)
  17. )
  18. filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
  19. obj = get_object_or_404(queryset, **filter_kwargs)
  20. # May raise a permission denied
  21. #检验单挑数据的权限
  22. self.check_object_permissions(self.request, obj)
  23. return obj
  24. ···················check_object_permissions··········
  25. def check_object_permissions(self, request, obj):
  26. """
  27. Check if the request should be permitted for a given object.
  28. Raises an appropriate exception if the request is not permitted.
  29. """
  30. for permission in self.get_permissions():
  31. if not permission.has_object_permission(request, self, obj):
  32. self.permission_denied(
  33. request, message=getattr(permission, 'message', None)
  34. )
  35. 执行has_object_permission
  36. def has_object_permission(self, request, view, obj):
  37. return True

版本认证权限执行流程

  1. 1.首先所有方法都执行父类的apiview方法
  2. 2.执行dispatch方法
  3. 3.进行
  4. def get_authenticators(self):
  5. return [auth() for auth in self.authentication_classes]
  6. 4.
  7. intiail request.user

如果代码中出现了CSRF使用装饰器即可

  1. from django.views.decorators.csrf import csrf_exempt
  2. from django.utils.decorators import method_decorator
  3. def csrf_exempt(view_func):
  4. """
  5. Marks a view function as being exempt from the CSRF view protection.
  6. """
  7. # We could just do view_func.csrf_exempt = True, but decorators
  8. # are nicer if they don't have side-effects, so we return a new
  9. # function.
  10. def wrapped_view(*args, **kwargs):
  11. return view_func(*args, **kwargs)
  12. wrapped_view.csrf_exempt = True
  13. return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)

drf访问频率的限制

  1. - 匿名用户,用IP作为用户唯一标记,但如果用户换代理IP,无法做到真正的限制。
  2. - 登录用户,用用户名或用户ID做标识。可以做到真正的限制

知识点

  1. {
  2. throttle_anon_1.1.1.1:[100121340,],
  3. 1.1.1.2:[100121251,100120450,]
  4. }
  5. 限制:60s能访问3
  6. 来访问时:
  7. 1.获取当前时间 100121280
  8. 2.100121280-60 = 100121220,小于100121220所有记录删除全部剔除
  9. 3.判断1分钟以内已经访问多少次了? 4
  10. 判断访问次数
  11. 4.无法访问
  12. 停一会
  13. 来访问时:
  14. 1.获取当前时间 100121340
  15. 2.100121340-60 = 100121280,小于100121280所有记录删除
  16. 3.判断1分钟以内已经访问多少次了? 0
  17. 4.可以访问

执行流程

  1. 在视图类中配置 throttle_classes= [] 这是一个列表
  2. 实现 allow_request 方法 wait 是一个提示方法
  3. 返回 True/False
  4. True 可以继续访问,
  5. False 表示限制
  6. 全局配置
  7. DEFAULT_THROTTLE_CLASSE,节流限制类
  8. DEFAULT_THROTTLE_RATES 表示频率限制,比如 10/m 表示 每分钟 10
  9. 源码在 initial 中实现 check_throttles 方法
  10. 在进行节流之前已经做了版本认证权限
  11. #dispatch分发
  12. def initial(self, request, *args, **kwargs):
  13. #版本
  14. version, scheme = self.determine_version(request, *args, **kwargs)
  15. request.version, request.versioning_scheme = version, scheme
  16. # Ensure that the incoming request is permitted
  17. #认证
  18. self.perform_authentication(request)
  19. #权限
  20. self.check_permissions(request)
  21. #频率限制
  22. self.check_throttles(request)
  23. 1.先找allow_request本类没有去父类找 dispatch
  24. 2.执行对应的rate获取对应scope 节流的频率
  25. 2.key是获取ip
  26. 3.history是获取ip地址 获取对应的访问时间记录
  27. '''
  28. self.history = self.cache.get(self.key, [])
  29. '''
  30. 4.对应的访问记录等于ture获取到值,
  31. 把当前的时间减去一个自己设定的时间戳
  32. '''
  33. while self.history and self.history[-1] <= self.now - self.duration:
  34. #条件满足 把最后一个值删除
  35. #再去循环判断
  36. self.history.pop()
  37. '''
  38. 5.然后判断访问次数有没有大于自己设定的值
  39. '''
  40. if len(self.history) >= self.num_requests:
  41. 满足条件走这
  42. return self.throttle_failure()
  43. 不满足条件走这
  44. return self.throttle_success()
  45. '''
  46. 6.成功 def throttle_success(self):
  47. """
  48. Inserts the current request's timestamp along with the key
  49. into the cache.
  50. """
  51. self.history.insert(0, self.now)
  52. self.cache.set(self.key, self.history, self.duration)
  53. return True
  54. 6.失败
  55. def throttle_failure(self):
  56. """
  57. Called when a request to the API has failed due to throttling.
  58. """
  59. return False#不可以访问
  60. 7如果返回false进入等待时间
  61. def wait(self):
  62. """
  63. Returns the recommended next request time in seconds.
  64. """
  65. if self.history:
  66. remaining_duration = self.duration - (self.now - self.history[-1])
  67. else:
  68. remaining_duration = self.duration
  69. available_requests = self.num_requests - len(self.history) + 1
  70. if available_requests <= 0:
  71. return None
  72. return remaining_duration / float(available_requests)

源码

  1. #dispatch分发
  2. def initial(self, request, *args, **kwargs):
  3. #版本
  4. version, scheme = self.determine_version(request, *args, **kwargs)
  5. request.version, request.versioning_scheme = version, scheme
  6. # Ensure that the incoming request is permitted
  7. #认证
  8. self.perform_authentication(request)
  9. #权限
  10. self.check_permissions(request)
  11. #频率限制
  12. self.check_throttles(request)
  13. def check_throttles(self, request):
  14. throttle_durations = []
  15. for throttle in self.get_throttles():
  16. #找到当前类的allow_request
  17. if not throttle.allow_request(request, self):
  18. throttle_durations.append(throttle.wait())
  19. if throttle_durations:
  20. durations = [
  21. duration for duration in throttle_durations
  22. if duration is not None
  23. ]
  24. duration = max(durations, default=None)
  25. self.throttled(request, duration)
  26. #执行类的allow_request
  27. def allow_request(self, request, view):
  28. """
  29. Implement the check to see if the request should be throttled.
  30. On success calls `throttle_success`.
  31. On failure calls `throttle_failure`.
  32. """
  33. if self.rate is None:
  34. return True
  35. 获取
  36. '''
  37. def __init__(self):
  38. if not getattr(self, 'rate', None):
  39. self.rate = self.get_rate()
  40. self.num_requests, self.duration = self.parse_rate(self.rate)
  41. 当前这个类有一个获取rate的方法
  42. '''
  43. #执行get_rate
  44. 读取settings设置的配置文件
  45. '''
  46. def get_rate(self):
  47. #如果不设置会进行报错
  48. try:
  49. #设置了就进行键取值
  50. return self.THROTTLE_RATES[self.scope]
  51. except KeyError:
  52. msg = "No default throttle rate set for '%s' scope" % self.scope
  53. raise ImproperlyConfigured(msg)
  54. '''
  55. #通过键去取值/进行分割获取值
  56. '''
  57. def parse_rate(self, rate):
  58. if rate is None:
  59. return (None, None)
  60. num, period = rate.split('/')
  61. num_requests = int(num)
  62. duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
  63. return (num_requests, duration)
  64. '''
  65. #这步继续往下执行继承类的get_cache_key
  66. self.key = self.get_cache_key(request, view)
  67. #匿名
  68. #继承了class AnonRateThrottle(SimpleRateThrottle):
  69. '''
  70. scope = 'anon'
  71. def get_cache_key(self, request, view):
  72. if request.user.is_authenticated:
  73. return None # Only throttle unauthenticated requests.
  74. return self.cache_format % {
  75. 'scope': self.scope,
  76. 'ident': self.get_ident(request)
  77. }
  78. }
  79. #返回字符串格式化
  80. throttle_(匿名)anon_(ip地址的拼接)1.1.1.1:[100121340,],
  81. '''
  82. #根据用户进行判断 重写get_cache_key
  83. '''
  84. '''
  85. if self.key is None:
  86. return True
  87. self.history = self.cache.get(self.key, [])
  88. self.now = self.timer()
  89. # Drop any requests from the history which have now passed the
  90. # throttle duration
  91. while self.history and self.history[-1] <= self.now - self.duration:
  92. self.history.pop()
  93. #元组返回的值num_requests
  94. if len(self.history) >= self.num_requests:
  95. #不可以访问
  96. return self.throttle_failure()
  97. #可以访问
  98. return self.throttle_success()
  99. '''
  100. 6.成功 def throttle_success(self):
  101. #成功把访问的当前时间插入history
  102. self.history.insert(0, self.now)
  103. self.cache.set(self.key, self.history, self.duration)
  104. return True
  105. 6.失败
  106. def throttle_failure(self):
  107. """
  108. Called when a request to the API has failed due to throttling.
  109. """
  110. return False#不可以访问
  111. '''

默认配置文件写法settings

  1. REST_FRAMEWORK = {
  2. throttle_classes = [AnonRateThrottle,]
  3. "DEFAULT_THROTTLE_RATES":{"anon":"3/m"}
  4. #这样写的原因 源码
  5. #通过匿名
  6. scope = 'anon'
  7. def get_cache_key(self, request, view):
  8. if request.user.is_authenticated:
  9. return None # Only throttle unauthenticated requests.
  10. return self.cache_format % {
  11. 'scope': self.scope,
  12. 'ident': self.get_ident(request)
  13. }
  14. }
  15. #获取全局设置的步骤
  16. def __init__(self):
  17. if not getattr(self, 'rate', None):
  18. #第一步
  19. self.rate = self.get_rate()
  20. '''
  21. 以设置的键进行取值获取时间
  22. def get_rate(self):
  23. 如果不设置就进行报错
  24. try:
  25. return self.THROTTLE_RATES[self.scope]
  26. except KeyError:
  27. msg = "No default throttle rate set for '%s' scope" % self.scope
  28. raise ImproperlyConfigured(msg)
  29. '''
  30. self.num_requests, self.duration = self.parse_rate(self.rate)
  31. #后面设置值格式
  32. #例 "DEFAULT_THROTTLE_RATES":{"anon":"3/m"}
  33. 以/分割 前面是限制的次数 后面的是访问限制的时间
  34. '''
  35. def parse_rate(self, rate):
  36. if rate is None:
  37. return (None, None)
  38. num, period = rate.split('/')
  39. num_requests = int(num)
  40. duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
  41. return (num_requests, duration)
  42. '''
  43. 之后执行对应字典的取值
  44. key=throttle_(匿名)anon_ip地址的拼接)1.1.1.1:
  45. [100121340,],#值
  46. self.key = self.get_cache_key(request, view)
  47. if self.key is None:
  48. return True
  49. self.history = self.cache.get(self.key, [])
  50. self.now = self.timer()
  51. # Drop any requests from the history which have now passed the
  52. # throttle duration
  53. while self.history and self.history[-1] <= self.now - self.duration:
  54. self.history.pop()
  55. if len(self.history) >= self.num_requests:
  56. return self.throttle_failure()
  57. return self.throttle_success()

根据匿名用户和id进行判断

全局配置

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_THROTTLE_CLASSES': [
  3. 'api.utils.throttles.throttles.LuffyAnonRateThrottle',
  4. 'api.utils.throttles.throttles.LuffyUserRateThrottle',
  5. ],
  6. 'DEFAULT_THROTTLE_RATES': {
  7. #不重写的默认走这
  8. 'anon': '10/day',
  9. 'user': '10/day',
  10. 'luffy_anon': '10/m',
  11. 'luffy_user': '20/m',
  12. },
  13. }
  14. settings

url写法

  1. from django.conf.urls import url, include
  2. from web.views.s3_throttling import TestView
  3. urlpatterns = [
  4. url(r'^test/', TestView.as_view()),
  5. ]
  6. urls.py

settings写法局部

  1. REST_FRAMEWORK = {
  2. 'UNAUTHENTICATED_USER': None,
  3. 'UNAUTHENTICATED_TOKEN': None,
  4. 'DEFAULT_THROTTLE_RATES': {
  5. 'luffy_anon': '10/m',
  6. 'luffy_user': '20/m',
  7. },
  8. }
  9. settings.py

根据匿名ip或者user 进行判断

视图写法

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from rest_framework.throttling import SimpleRateThrottle
  6. class LuffyAnonRateThrottle(SimpleRateThrottle):
  7. """
  8. 匿名用户,根据IP进行限制
  9. """
  10. scope = "luffy_anon"
  11. def get_cache_key(self, request, view):
  12. # 用户已登录,则跳过 匿名频率限制
  13. if request.user:
  14. return None
  15. return self.cache_format % {
  16. 'scope': self.scope,
  17. 'ident': self.get_ident(request)
  18. }
  19. class LuffyUserRateThrottle(SimpleRateThrottle):
  20. """
  21. 登录用户,根据用户token限制
  22. """
  23. #重写scope
  24. scope = "luffy_user"
  25. def get_ident(self, request):
  26. """
  27. 认证成功时:request.user是用户对象;request.auth是token对象
  28. :param request:
  29. :return:
  30. """
  31. # return request.auth.token
  32. return "user_token"
  33. def get_cache_key(self, request, view):
  34. """
  35. 获取缓存key
  36. :param request:
  37. :param view:
  38. :return:
  39. """
  40. # 未登录用户,则跳过 Token限制
  41. if not request.user:
  42. return None
  43. return self.cache_format % {
  44. 'scope': self.scope,
  45. 'ident': self.get_ident(request)
  46. }
  47. class TestView(APIView):
  48. throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
  49. def get(self, request, *args, **kwargs):
  50. # self.dispatch
  51. print(request.user)
  52. print(request.auth)
  53. return Response('GET请求,响应内容')
  54. def post(self, request, *args, **kwargs):
  55. return Response('POST请求,响应内容')
  56. def put(self, request, *args, **kwargs):
  57. return Response('PUT请求,响应内容')

源码

class AnonRateThrottle(SimpleRateThrottle):
scope = 'anon'
def get_cache_key(self, request, view):
if request.user.is_authenticated:
return None
# Only throttle unauthenticated requests.

  1. return self.cache_format % {
  2. 'scope': self.scope,
  3. 'ident': self.get_ident(request)
  4. }

def get_cache_key(self, request, view):
return self.get_ident(request)#获取对应的ip值

````

settings

  1. # settings.py
  2. 'DEFAULT_THROTTLE_RATES': {
  3. 'Vistor': '3/m',
  4. 'User': '10/m'
  5. },

drf总结

django'中可以免除csrftoken的认证

  1. from django.views.decorators.csrf import csrf_exempt
  2. from django.shortcuts import HttpResponse
  3. @csrf_exempt def index(request):
  4. return HttpResponse('...')
  5. # index = csrf_exempt(index)
  6. urlpatterns = [
  7. url(r'^index/$',index),
  8. ]

drf中view进行csrftoken的认证

  1. urlpatterns = [ url(r'^login/$',account.LoginView.as_view()),
  2. ]
  3. class APIView(View):
  4. @classmethod
  5. def as_view(cls, **initkwargs):
  6. view = super().as_view(**initkwargs)
  7. view.cls = cls
  8. view.initkwargs = initkwargs
  9. # Note: session based authentication is explicitly CSRF validated,
  10. # all other authentication is CSRF exempt.
  11. return csrf_exempt(view)

1.写视图的方法

  • 第一种:原始APIView

    1. url(r'^login/$',account.LoginView.as_view()),
    1. from rest_framework.views import APIView
    2. from rest_framework.response import Response
    3. from rest_framework_jwt.settings import api_settings
    4. from rest_framework.throttling import AnonRateThrottle
    5. from api import models
    6. class LoginView(APIView):
    7. authentication_classes = []
    8. def post(self,request,*args,**kwargs):
    9. # 1.根据用户名和密码检测用户是否可以登录
    10. user = models.UserInfo.objects.filter(username=request.data.get('username'),password=request.data.get('password')).first()
    11. if not user:
    12. return Response({'code':10001,'error':'用户名或密码错误'})
    13. # 2. 根据user对象生成payload(中间值的数据)
    14. jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    15. payload = jwt_payload_handler(user)
    16. # 3. 构造前面数据,base64加密;中间数据base64加密;前两段拼接然后做hs256加密(加盐),再做base64加密。生成token
    17. jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    18. token = jwt_encode_handler(payload)
    19. return Response({'code': 10000, 'data': token})
  • 第二种:ListApiView等

    1. url(r'^article/$',article.ArticleView.as_view()),
    2. url(r'^article/(?P<pk>\d+)/$',article.ArticleDetailView.as_view()),
    1. from rest_framework.throttling import AnonRateThrottle
    2. from rest_framework.response import Response
    3. from rest_framework.generics import ListAPIView,RetrieveAPIView
    4. from api import models
    5. from api.serializer.article import ArticleSerializer,ArticleDetailSerializer
    6. class ArticleView(ListAPIView):
    7. authentication_classes = []
    8. # throttle_classes = [AnonRateThrottle,]
    9. queryset = models.Article.objects.all()
    10. serializer_class = ArticleSerializer
    11. class ArticleDetailView(RetrieveAPIView):
    12. authentication_classes = []
    13. queryset = models.Article.objects.all()
    14. serializer_class = ArticleDetailSerializer
  • 第三种:

    1. url(r'^article/$',article.ArticleView.as_view({"get":'list','post':'create'})),
    2. url(r'^article/(?P<pk>\d+)/$',article.ArticleView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))
    1. from rest_framework.viewsets import GenericViewSet
    2. from rest_framework.mixins import ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
    3. from api.serializer.article import ArticleSerializer,ArticleDetailSerializer
    4. class ArticleView(GenericViewSet,ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin):
    5. authentication_classes = []
    6. throttle_classes = [AnonRateThrottle,]
    7. queryset = models.Article.objects.all()
    8. serializer_class = None
    9. def get_serializer_class(self):
    10. pk = self.kwargs.get('pk')
    11. if pk:
    12. return ArticleDetailSerializer
    13. return ArticleSerializer

drf 相关知识点梳理

  1. 装饰器

    1. def outer(func):
    2. def inner(*args,**kwargs):
    3. return func(*args,**kwargs)
    4. return inner
    5. @outer
    6. def index(a1):
    7. pass
    8. index()
    1. def outer(func):
    2. def inner(*args,**kwargs):
    3. return func(*args,**kwargs)
    4. return inner
    5. def index(a1):
    6. pass
    7. index = outer(index)
    8. index()
  2. django中可以免除csrftoken认证

    1. from django.views.decorators.csrf import csrf_exempt
    2. from django.shortcuts import HttpResponse
    3. @csrf_exempt
    4. def index(request):
    5. return HttpResponse('...')
    6. # index = csrf_exempt(index)
    7. urlpatterns = [
    8. url(r'^index/$',index),
    9. ]
    1. urlpatterns = [
    2. url(r'^login/$',account.LoginView.as_view()),
    3. ]
    4. class APIView(View):
    5. @classmethod
    6. def as_view(cls, **initkwargs):
    7. view = super().as_view(**initkwargs)
    8. view.cls = cls
    9. view.initkwargs = initkwargs
    10. # Note: session based authentication is explicitly CSRF validated,
    11. # all other authentication is CSRF exempt.
    12. return csrf_exempt(view)
  3. 面向对象中基于继承+异常处理来做的约束

    1. class BaseVersioning:
    2. def determine_version(self, request, *args, **kwargs):
    3. raise NotImplementedError("must be implemented")
    4. class URLPathVersioning(BaseVersioning):
    5. def determine_version(self, request, *args, **kwargs):
    6. version = kwargs.get(self.version_param, self.default_version)
    7. if version is None:
    8. version = self.default_version
    9. if not self.is_allowed_version(version):
    10. raise exceptions.NotFound(self.invalid_version_message)
    11. return version
  4. 面向对象封装

    1. class Foo(object):
    2. def __init__(self,name,age):
    3. self.name = name
    4. self.age = age
    5. obj = Foo('汪洋',18)
    1. class APIView(View):
    2. def dispatch(self, request, *args, **kwargs):
    3. self.args = args
    4. self.kwargs = kwargs
    5. request = self.initialize_request(request, *args, **kwargs)
    6. self.request = request
    7. ...
    8. def initialize_request(self, request, *args, **kwargs):
    9. """
    10. Returns the initial request object.
    11. """
    12. parser_context = self.get_parser_context(request)
    13. return Request(
    14. request,
    15. parsers=self.get_parsers(),
    16. authenticators=self.get_authenticators(), # [MyAuthentication(),]
    17. negotiator=self.get_content_negotiator(),
    18. parser_context=parser_context
    19. )
  5. 面向对象继承

    1. class View(object):
    2. pass
    3. class APIView(View):
    4. def dispatch(self):
    5. method = getattr(self,'get')
    6. method()
    7. class GenericAPIView(APIView):
    8. serilizer_class = None
    9. def get_seriliser_class(self):
    10. return self.serilizer_class
    11. class ListModelMixin(object):
    12. def get(self):
    13. ser_class = self.get_seriliser_class()
    14. print(ser_class)
    15. class ListAPIView(ListModelMixin,GenericAPIView):
    16. pass
    17. class UserInfoView(ListAPIView):
    18. pass
    19. view = UserInfoView()
    20. view.dispatch()
    1. class View(object):
    2. pass
    3. class APIView(View):
    4. def dispatch(self):
    5. method = getattr(self,'get')
    6. method()
    7. class GenericAPIView(APIView):
    8. serilizer_class = None
    9. def get_seriliser_class(self):
    10. return self.serilizer_class
    11. class ListModelMixin(object):
    12. def get(self):
    13. ser_class = self.get_seriliser_class()
    14. print(ser_class)
    15. class ListAPIView(ListModelMixin,GenericAPIView):
    16. pass
    17. class UserInfoView(ListAPIView):
    18. serilizer_class = "汪洋"
    19. view = UserInfoView()
    20. view.dispatch()
    1. class View(object):
    2. pass
    3. class APIView(View):
    4. def dispatch(self):
    5. method = getattr(self,'get')
    6. method()
    7. class GenericAPIView(APIView):
    8. serilizer_class = None
    9. def get_seriliser_class(self):
    10. return self.serilizer_class
    11. class ListModelMixin(object):
    12. def get(self):
    13. ser_class = self.get_seriliser_class()
    14. print(ser_class)
    15. class ListAPIView(ListModelMixin,GenericAPIView):
    16. pass
    17. class UserInfoView(ListAPIView):
    18. def get_seriliser_class(self):
    19. return "咩咩"
    20. view = UserInfoView()
    21. view.dispatch()
  6. 反射

    1. class View(object):
    2. def dispatch(self, request, *args, **kwargs):
    3. # Try to dispatch to the right method; if a method doesn't exist,
    4. # defer to the error handler. Also defer to the error handler if the
    5. # request method isn't on the approved list.
    6. if request.method.lower() in self.http_method_names:
    7. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    8. else:
    9. handler = self.http_method_not_allowed
    10. return handler(request, *args, **kwargs)
  7. 发送ajax请求

    1. $.ajax({
    2. url:'地址',
    3. type:'GET',
    4. data:{...},
    5. success:function(arg){
    6. console.log(arg);
    7. }
    8. })
  8. 浏览器具有 "同源策略的限制",导致 发送ajax请求 + 跨域 存在无法获取数据。

    • 简单请求,发送一次请求。
    • 复杂请求,先options请求做预检,然后再发送真正请求
    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Title</title>
    6. </head>
    7. <body>
    8. <h1>常鑫的网站</h1>
    9. <p>
    10. <input type="button" value="点我" onclick="sendMsg()">
    11. </p>
    12. <p>
    13. <input type="button" value="点他" onclick="sendRemoteMsg()">
    14. </p>
    15. <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    16. <script>
    17. function sendMsg() {
    18. $.ajax({
    19. url:'/msg/',
    20. type:'GET',
    21. success:function (arg) {
    22. console.log(arg);
    23. }
    24. })
    25. }
    26. function sendRemoteMsg() {
    27. $.ajax({
    28. url:'http://127.0.0.1:8002/json/',
    29. type:'GET',
    30. success:function (arg) {
    31. console.log(arg);
    32. }
    33. })
    34. }
    35. </script>
    36. </body>
    37. </html>
  9. 如何解决ajax+跨域?

    1. CORS,跨站资源共享,本质:设置响应头。
  10. 常见的Http请求方法

    1. get
    2. post
    3. put
    4. patch
    5. delete
    6. options
  11. http请求中Content-type请起头

    1. 情况一:
    2. content-type:x-www-form-urlencode
    3. name=alex&age=19&xx=10
    4. request.POSTrequest.body中均有值。
    5. 情况二:
    6. content-type:application/json
    7. {"name":"ALex","Age":19}
    8. request.POST没值
    9. request.body有值。
  12. django中F查询

  13. django中获取空Queryset

    1. models.User.object.all().none()
  14. 基于django的fbv和cbv都能实现遵循restful规范的接口

    1. def user(request):
    2. if request.metho == 'GET':
    3. pass
    4. class UserView(View):
    5. def get()...
    6. def post...
  15. 基于django rest framework框架实现restful api的开发。

    1. - 免除csrf认证
    2. - 视图(APIViewListAPIViewListModelMinx
    3. - 版本
    4. - 认证
    5. - 权限
    6. - 节流
    7. - 解析器
    8. - 筛选器
    9. - 分页
    10. - 序列化
    11. - 渲染器
  16. 简述drf中认证流程?

    1. 1.用户发来请求优先执行dispatch方法
    2. 2.内部会封装reqeustd1
  17. 简述drf中节流的实现原理以及过程?匿名用户/非匿名用户 如何实现频率限制?

  18. GenericAPIView视图类的作用?

    1. 他提供了一些规则,例如:
    2. class GenericAPIView(APIView):
    3. serializer_class = None
    4. queryset = None
    5. lookup_field = 'pk'
    6. filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    7. pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    8. def get_queryset(self):
    9. return self.queryset
    10. def get_serializer_class(self):
    11. return self.serializer_class
    12. def filter_queryset(self, queryset):
    13. for backend in list(self.filter_backends):
    14. queryset = backend().filter_queryset(self.request, queryset, self)
    15. return queryset
    16. @property
    17. def paginator(self):
    18. if not hasattr(self, '_paginator'):
    19. if self.pagination_class is None:
    20. self._paginator = None
    21. else:
    22. self._paginator = self.pagination_class()
    23. return self._paginator
    24. 他相当于提供了一些规则,建议子类中使用固定的方式获取数据,例如:
    25. class ArticleView(GenericAPIView):
    26. queryset = models.User.objects.all()
    27. def get(self,request,*args,**kwargs):
    28. query = self.get_queryset()
    29. 我们可以自己继承GenericAPIView来实现具体操作,但是一般不会,因为更加麻烦。
    30. GenericAPIView主要是提供给drf内部的 ListAPIViewCreate....
    31. class ListModelMixin:
    32. def list(self, request, *args, **kwargs):
    33. queryset = self.filter_queryset(self.get_queryset())
    34. page = self.paginate_queryset(queryset)
    35. if page is not None:
    36. serializer = self.get_serializer(page, many=True)
    37. return self.get_paginated_response(serializer.data)
    38. serializer = self.get_serializer(queryset, many=True)
    39. return Response(serializer.data)
    40. class ListAPIView(mixins.ListModelMixin,GenericAPIView):
    41. def get(self, request, *args, **kwargs):
    42. return self.list(request, *args, **kwargs)
    43. class MyView(ListAPIView):
    44. queryset = xxxx
    45. ser...
    1. 总结:GenericAPIView主要为drf内部帮助我们提供增删改查的类LIstAPIViewCreateAPIViewUpdateAPIView、提供了执行流程和功能,我们在使用drf内置类做CURD时,就可以通过自定义 静态字段(类变量)或重写方法(get_querysetget_serializer_class)来进行更高级的定制。
  19. jwt以及其优势。

    1. jwt前后端分离 用于用户认证
    2. jwt的实现原理:
    3. -用户登陆成功,会给前端返回一个tokon值。
    4. token值只在前端保存
    5. token值分为
    6. 一段类型和算法信息
    7. 第二段用户信息和超时时间
    8. 第三段前两段数据拼接之后进行has256再次加密+base64url
  20. 序列化时many=True和many=False的区别?

  21. 应用DRF中的功能进行项目开发

    1. *****
    2. 解析器:request.query_parmas/request.data
    3. 视图
    4. 序列化
    5. 渲染器:Response
    6. ****
    7. request对象封装
    8. 版本处理
    9. 分页处理
    10. ***
    11. 认证
    12. 权限
    13. 节流
    • 基于APIView实现呼啦圈
    • 继承ListAPIView+ GenericViewSet,ListModelMixin实现呼啦圈

跨域

  • 域相同,永远不会存在跨域。

    • crm,非前后端分离,没有跨域。
    • 路飞学城,前后端分离,没有跨域(之前有,现在没有)。
  • 域不同时,才会存在跨域。
    • l拉勾网,前后端分离,存在跨域(设置响应头解决跨域)
  1. 由于浏览器具有同源策略的限制
  2. ajax请求的限制
  3. 同源同端口
  4. 不同源就是跨域
  5. 写了/api 不跨域 api访问django
  6. api.xx.com跨域了访问django

简单请求

发一次请求

  1. 设置响应头就可以解决
  2. from django.shortcuts import render,HttpResponse
  3. def json(request):
  4. response = HttpResponse("JSONasdfasdf")
  5. response['Access-Control-Allow-Origin'] = "*"
  6. return response

复杂请求

预检option

请求

html写法

写法

  1. from django.views.decorators.csrf import csrf_exempt
  2. from django.utils.decorators import method_decorator
  3. @csrf_exempt
  4. def put_json(request):
  5. response = HttpResponse("JSON复杂请求")
  6. if request.method == 'OPTIONS':
  7. # 处理预检
  8. response['Access-Control-Allow-Origin'] = "*"
  9. response['Access-Control-Allow-Methods'] = "PUT"
  10. return response
  11. elif request.method == "PUT":
  12. return response

解决跨域:CORS

  1. 本质在数据返回值设置响应头
  2. from django.shortcuts import render,HttpResponse
  3. def json(request):
  4. response = HttpResponse("JSONasdfasdf")
  5. response['Access-Control-Allow-Origin'] = "*"
  6. return response

通过jsonp

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <p>
  9. <input type="button" onclick="Jsonp1();" value='提交'/>
  10. </p>
  11. <p>
  12. <input type="button" onclick="Jsonp2();" value='提交'/>
  13. </p>
  14. <script type="text/javascript" src="jquery-1.12.4.js"></script>
  15. <script>
  16. function Jsonp1(){
  17. var tag = document.createElement('script');
  18. tag.src = "http://c2.com:8000/test/";
  19. document.head.appendChild(tag);
  20. document.head.removeChild(tag);
  21. }
  22. function Jsonp2(){
  23. $.ajax({
  24. url: "http://c2.com:8000/test/",
  25. type: 'GET',
  26. dataType: 'JSONP',
  27. success: function(data, statusText, xmlHttpRequest){
  28. console.log(data);
  29. }
  30. })
  31. }
  32. </script>
  33. </body>
  34. </html>

总结

  1. 条件:
  2. 1、请求方式:HEADGETPOST
  3. 2、请求头信息:
  4. Accept
  5. Accept-Language
  6. Content-Language
  7. Last-Event-ID
  8. Content-Type 对应的值是以下三个中的任意一个
  9. application/x-www-form-urlencoded
  10. multipart/form-data
  11. text/plain
  12. 注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

总结

  1. 由于浏览器具有“同源策略”的限制,所以在浏览器上跨域发送Ajax请求时,会被浏览器阻止。
  2. 解决跨域
    • 不跨域
    • CORS(跨站资源共享,本质是设置响应头来解决)。
      • 简单请求:发送一次请求
      • 复杂请求:发送两次请求

部署 collectstaic 收集静态文件

jwt

  1. 用于在前后端分离时,实现用户登录相关。

1.知识点

1.2jwt代替token 进行优化

  1. 用户登录成功之后,生成一个随机字符串,给前端。
  2. - 生成随机字符串
  3. 加密信息
  4. #{typ:"jwt","alg":'HS256'}
  5. # 加密手段segments.append(base64url_encode(json_header))
  6. 98qow39df0lj980945lkdjflo.
  7. #第二部分的信息 {id:1,username:'alx','exp':10}
  8. #加密手段segments.append(base64url_encode(payload))
  9. saueoja8979284sdfsdf.
  10. #两个密文拼接加盐
  11. asiuokjd978928374
  12. - 类型信息通过base64加密
  13. - 数据通过base64加密
  14. - 两个密文拼接在h256加密+加盐
  15. - 给前端返回token值只在前端
  16. token是由。分割的三段组成
  17. - 第一段:类型和算法信息
  18. - 第二段。 用户的信息和超时时间
  19. - 第三段:hs256(前两段拼接)加密 + base64url
  20. - 以后前端再次发来信息时
  21. - 超时验证
  22. - token合法性校验
  23. 前端获取随机字符串之后,保留起来。
  24. 以后再来发送请求时,携带98qow39df0lj980945lkdjflo.saueoja8979284sdfsdf.asiuokjd978928375
  25. 后端接收到之后
  26. 1.取出第二部分进行时间的判断
  27. 2. 把前面两个进行加密对第三个值进行加密
  28. - token只在前端保存,后端只负责校验。
  29. - 内部集成了超时时间,后端可以根据时间进行校验是否超时。 - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。
  30. 一般在前后端分离时,用于做用户认证(登录)使用的技术。
  31. jwt的实现原理:
  32. - 用户登录成功之后,会给前端返回一段token
  33. - token是由.分割的三段组成。
  34. - 第一段:类型和算法信心
  35. - 第二段:用户信息+超时时间
  36. - 第三段:hs256(前两段拼接)加密 + base64url
  37. - 以后前端再次发来信息时
  38. - 超时验证
  39. - token合法性校验
  40. 优势:
  41. - token只在前端保存,后端只负责校验。
  42. - 内部集成了超时时间,后端可以根据时间进行校验是否超时。
  43. - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。

1.2token

  1. 用户登陆成功之后,生成一个随机字符串,自己保留一份,给前端返回一份。
  2. 以后前端再来发请求时,需要携带字符串
  3. 后端对字符串进行校验

流程

1.安装

  1. pip3 install djangorestframework-jwt

2.注册

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'api.apps.ApiConfig',
  9. 'rest_framework',
  10. 'rest_framework_jwt']

3.源码剖析和实现流程

  1. from rest_framework_jwt.views import obtain_jwt_token

具体流程

  1. 用户信息加密
  2. jwt_payload_hander = api_settings.JWT_PAYLOAD_HANDLER
  3. 第三段信息的加密
  4. jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
  5. #解密
  6. jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
  7. def jwt_payload_handler(user):
  8. username_field = get_username_field()
  9. username = get_username(user)
  10. warnings.warn(
  11. 'The following fields will be removed in the future: '
  12. '`email` and `user_id`. ',
  13. DeprecationWarning
  14. )
  15. payload = {
  16. 'user_id': user.pk,
  17. 'username': username,
  18. 'exp': datetime.utcnow() +
  19. #默认5分钟
  20. api_settings.JWT_EXPIRATION_DELTA
  21. #如果有email会把email配置上
  22. if hasattr(user, 'email'):
  23. payload['email'] = user.email
  24. if isinstance(user.pk, uuid.UUID):
  25. #如果有user_id会把pk值配置上
  26. payload['user_id'] = str(user.pk)
  27. payload[username_field] = username
  28. #源码
  29. settings= 'JWT_EXPIRATION_DELTA':datetime.timedelta(seconds=300)
  30. ,
  31. }

加密的具体实现流程

  1. api_settings.JWT_ENCODE_HANDLER -->
  2. 加密的具体实现
  3. def jwt_encode_handler(payload):
  4. #payload传入
  5. key = api_settings.JWT_PRIVATE_KEY or jwt_get_secret_key(payload)
  6. #加盐
  7. #SECRET_KEY = '+gr4bbq8e$yqbd%n_h)2(osz=bmk1x2+o6+w5g@a4r1#3%q1n*'
  8. return jwt.encode(
  9. payload,#类型信息头信息
  10. key,#加盐
  11. #默认封装传入了hs256
  12. api_settings.JWT_ALGORITHM
  13. # 'JWT_ALGORITHM': 'HS256',
  14. ).decode('utf-8')
  15. encode默认继承父类的
  16. 父类的encode方法
  17. # Header
  18. header = {'typ': self.header_typ, 'alg': algorithm}
  19. #self.header_typ #-- 》 header_typ = 'JWT'
  20. signing_input = b'.'.join(segments)#把类型信息和数据用.的形式拼接到了一起
  21. try:
  22. alg_obj = self._algorithms[algorithm]#执行算法
  23. key = alg_obj.prepare_key(key)
  24. signature = alg_obj.sign(signing_input, key)#把拼接起来的值进行二次加密 成为第三个信息
  25. '''
  26. except KeyError:
  27. if not has_crypto and algorithm in requires_cryptography:
  28. raise NotImplementedError(
  29. "Algorithm '%s' could not be found. Do you have cryptography "
  30. "installed?" % algorithm
  31. )
  32. else:
  33. raise NotImplementedError('Algorithm not supported')
  34. '''
  35. segments.append(base64url_encode(signature))#再把第三个信息放入列表 对第三个信息进行base64进行加密
  36. return b'.'.join(segments)#用.的形式再把第三个数据拼接起来 进行返回
  37. 98qow39df0lj980945lkdjflo.saueoja8979284sdfsdf.asiuokjd978928375

解密

  1. token分割成 header_segmentpayload_segmentcrypto_segment 三部分
  2. 对第一部分header_segment进行base64url解密,得到header
  3. 对第二部分payload_segment进行base64url解密,得到payload
  4. 对第三部分crypto_segment进行base64url解密,得到signature
  5. 对第三部分signature部分数据进行合法性校验
  6. 拼接前两段密文,即:signing_input
  7. 从第一段明文中获取加密算法,默认:HS256
  8. 使用 算法+盐 signing_input 进行加密,将得到的结果和signature密文进行比较。

jwt的原理和优势

  1. 一般在前后端分离时,用于做用户认证(登录)使用的技术。
  2. jwt的实现原理:
  3. - 用户登录成功之后,会给前端返回一段token
  4. - token是由.分割的三段组成。
  5. - 第一段:类型和算法信心
  6. - 第二段:用户信息+超时时间
  7. - 第三段:hs256(前两段拼接)加密 + base64url
  8. - 以后前端再次发来信息时
  9. - 超时验证
  10. - token合法性校验
  11. #优势:
  12. - token只在前端保存,后端只负责校验。
  13. - 内部集成了超时时间,后端可以根据时间进行校验是否超时。
  14. - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。

具体使用

用户登陆

  1. import uuid
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework.versioning import URLPathVersioning
  5. from rest_framework import status
  6. from api import models
  7. class LoginView(APIView):
  8. """
  9. 登录接口
  10. """
  11. def post(self,request,*args,**kwargs):
  12. # 基于jwt的认证
  13. # 1.去数据库获取用户信息
  14. from rest_framework_jwt.settings import api_settings
  15. #头信息
  16. jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
  17. #第三个数据的加密
  18. jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
  19. user = models.UserInfo.objects.filter(**request.data).first()
  20. if not user:
  21. return Response({'code':1000,'error':'用户名或密码错误'})
  22. '''
  23. 'user_id': user.pk,
  24. 'username': username,
  25. 'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
  26. '''
  27. #头信息的处理
  28. payload = jwt_payload_handler(user)
  29. #对三段信息的编码 加密
  30. token = jwt_encode_handler(payload)
  31. return Response({'code':1001,'data':token})
  32. #第二种方式
  33. class LoginView(APIView):
  34. authentication_classes = []
  35. def post(self,request,*args,**kwargs):
  36. # 1.根据用户名和密码检测用户是否可以登录
  37. user = models.UserInfo.objects.filter(username=request.data.get('username'),password=request.data.get('password')).first()
  38. if not user:
  39. return Response({'code':10001,'error':'用户名或密码错误'})
  40. # 2. 根据user对象生成payload(中间值的数据)
  41. jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
  42. payload = jwt_payload_handler(user)
  43. # 3. 构造前面数据,base64加密;中间数据base64加密;前两段拼接然后做hs256加密(加盐),再做base64加密。生成token
  44. jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
  45. token = jwt_encode_handler(payload)
  46. return Response({'code': 10000, 'data': token})

用户认证

开始解码

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. # from rest_framework.throttling import AnonRateThrottle,BaseThrottle
  4. class ArticleView(APIView):
  5. # throttle_classes = [AnonRateThrottle,]
  6. def get(self,request,*args,**kwargs):
  7. # 获取用户提交的token,进行一步一步校验
  8. import jwt
  9. from rest_framework import exceptions
  10. from rest_framework_jwt.settings import api_settings
  11. #进行解码
  12. jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
  13. #获取到加密之后的字符串
  14. jwt_value = request.query_params.get('token')
  15. try:
  16. #对token进行解密
  17. payload = jwt_decode_handler(jwt_value)
  18. #判断签名是否过期
  19. except jwt.ExpiredSignature:
  20. msg = '签名已过期'
  21. raise exceptions.AuthenticationFailed(msg)
  22. #判断是否被篡改
  23. except jwt.DecodeError:
  24. msg = '认证失败'
  25. raise exceptions.AuthenticationFailed(msg)
  26. except jwt.InvalidTokenError:
  27. raise exceptions.AuthenticationFailed()
  28. print(payload)
  29. return Response('文章列表')

settings设置

  1. 'JWT_EXPIRATION_DELTA':datetime.timedelta(seconds=300)
  2. #默认五分钟有效
  3. #自定义
  4. import datetime
  5. JWT_AUTH = {
  6. "JWT_EXPIRATION_DELTA":datetime.timedelta(minutes=10)
  7. }

视图的mixins写法

ListModelMixin

  1. 执行list方法

paramiko

用于帮助开发者通过代码远程连接服务器

公钥和私钥进行连接服务器 比较方便

  1. $ssh -copy-id -i .ssh /id ras.pub

基于用户名密码连接:

需要一直去使用输入

  1. import paramiko
  2. # 创建SSH对象
  3. ssh = paramiko.SSHClient()
  4. # 允许连接不在know_hosts文件中的主机
  5. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  6. # 连接服务器
  7. ssh.connect(hostname='192.168.159.128', port=22, username='root', password='ziwen123')
  8. # 执行命令
  9. stdin, stdout, stderr = ssh.exec_command('df')
  10. # 获取命令结果
  11. result = stdout.read()
  12. # 关闭连接
  13. ssh.close()

发送数据
import requests

requests.post(
url = "http://127.0.0.1:8000/api/v1/server/",
json={'server':data,'host':'192.16.12.66'}
)
```

远程执行命令【公钥和私钥】(公钥必须提前上传到服务器)

  1. import paramiko
  2. private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
  3. # 创建SSH对象
  4. ssh = paramiko.SSHClient()
  5. # 允许连接不在know_hosts文件中的主机
  6. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  7. # 连接服务器
  8. ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)
  9. # 执行命令
  10. stdin, stdout, stderr = ssh.exec_command('df')
  11. # 获取命令结果
  12. result = stdout.read()
  13. # 关闭连接
  14. ssh.close()

远程上传和下载文件【用户名和密码】

  1. import paramiko
  2. transport = paramiko.Transport(('hostname',22))
  3. transport.connect(username='wupeiqi',password='123')
  4. sftp = paramiko.SFTPClient.from_transport(transport)
  5. # 将location.py 上传至服务器 /tmp/test.py
  6. sftp.put('/tmp/location.py', '/tmp/test.py')
  7. # 将remove_path 下载到本地 local_path
  8. sftp.get('remove_path', 'local_path')
  9. transport.close()

远程上传和下载文件【公钥和私钥】

  1. import paramiko
  2. private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
  3. transport = paramiko.Transport(('hostname', 22))
  4. transport.connect(username='wupeiqi', pkey=private_key )
  5. sftp = paramiko.SFTPClient.from_transport(transport)
  6. # 将location.py 上传至服务器 /tmp/test.py
  7. sftp.put('/tmp/location.py', '/tmp/test.py')
  8. # 将remove_path 下载到本地 local_path
  9. sftp.get('remove_path', 'local_path')
  10. transport.close()

补充:通过私钥字符串也可以连接远程服务器

  1. key = """-----BEGIN RSA PRIVATE KEY----MIIG5AIBAAKCAYEAu0fkMInsVRnIBSiZcVYhKuccWCh6hapYgB1eSOWZLz3+xFGy G5p2z8HgiHzfT838gAm+5OajuyAuE4+fHI77LXSg+pLbr1FhPVKAP+nbsnLgvHty ykZmt74CKKvZ08wdM7eUWJbkdpRNWmkwHBi99LeO0zYbHdXQ+m0P9EiWfdacJdAV RDVCghQo1/IpfSUECpfQK1Hc0126vI8nhtrvT3V9qF420U1fwW9GJrODl71WRqvJ BgSsKsjV16f0RKARESNmtA2vEdvMeutttZoO4FbvZ+iLKpcRM4LGm2+odryr8ijv dCPCLVvoDExOPuqP1dgt5MWcCWf6ZNhMwAs/yvRHAKetvo5gtz8YvzwlikopCLM7 bS6C6woyppMHfIPjoGJ6JuKpeaWtAgugOw/oVvj1rRYoCv48R13NftqhkFD1KD8z km9CjDC8hv+2DmIedtjvVwUz2QF4PN/RC/i1jo3+3rbP1DLu9emTHiortBBrpQ5o K+y4Rzv+6NusD6DHAgMBAAECggGBAJ4hTaNOUaZpZmI0rZrsxoSbL2ugghNqid9i 7MFQW89v4TWSZXi5K6iwYw3bohKYMqNJl01fENBnk4AgvJA4ig0PdP0eEzAs3pYQ mwlcRIygQvHiqkHwv7pVTS1aLUqQBfgtAazre2xEPCwitOSEX5/JfWcJQEwoxZMt k1MIF0mZc67Zy5sT/Vwn+XScnDt2jbsEBFkPfg1aDto3ZYCQS5Aj/D21j0OauUdy 1SDIYkw1Kivx0IKsX1Kg0S6OOcnX/B6YrJvisrlQDeZnWlTsTyKSVTekIybJjUHE ZgLIIbifSbTW1Bv1iCkDAJBd4Cj4txjXPIgea9ylZ39wSDSV5Pxu0t/M3YbdA26j quVFCKqskNOC+cdYrdtVSij2Ypwov67HYsXC/w32oKO7tiRqy51LAs/WXMwQeS5a 8oWDZLiYIntY4TCYTVOvFlLRtXb+1SbwWKjJdjKvdChv4eo/Ov5JEXD2FVbVC/5E Qo3jyjIrt1lrwXUdpJa0/iz4UV33wQKBwQDprCPZVCI7yK/BWTmUvCcupotNk6CC +QIKDcvVxz63YFD5nXto4uG7ywXR6pEwOwmycO0CBuouvlPdSioQ3RYi6k0EO3Ch 9dybC5RZ3MENBHROHvU3mp01EWPUYnXAwNpvknujJqfXMxyURZvvox7hOnu/s3m4 C3eCBrMMg+uqNZDbLqAymw3pMGhHVWjy5oO8eLuLeJv6er+XoSSPNb21Da7StdQS fBPQ1H0/+RXnhFJOzANc4mRZcXMCNGVZX6MCgcEAzSz3evuCRQ47AaSOrDd89jAw PgpT+PG4gWw1jFZqHTbQ8MUl3YnElOVoaWRdIdDeslg9THg1cs5Yc9RrbIibyQjV F9k/DlXGo0F//Mgtmr7JkLP3syRl+EedRbu2Gk67XDrV7XIvhdlsEuSnEK9xOiB6 ngewM0e4TccqlLsb6u7RNMU9IjMu/iMcBXKsZ9Cr/DENmGQlTaRVt7G6UcAYGNgQ toMoCQWjR/HihlZHssLBj9U8uPyD38HKGy2OoXyNAoHBAKQzv9lHYusJ4l+G+IyJ DyucAsXX2HJQ0tsHyNYHtg2cVCqkPIV+8UtKpmNVZwMyaWUIL7Q98bA5NKuLIzZI dfbBGK/BqStWntgg8fWXx90C5UvEO2MAdjpFZxZmvgJeQuEmWVVTo5v4obubkrF5 ughhVXZng0AOZsNrO8Suqxsnmww6nn4RMVxNFOoTnbUawTXezUN71HfWa+38Ybl0 9UNWQyR0e3slz7LurrkWqwrOlBwlBrPtrsCflUbWVOXR6wKBwDFq+Dy14V2SnOG7 aeXPA5kkaCo5QJqAVglOL+OaWLqqnk6vnXwrl56pVqmz0762WT0phbIqbe02CBX1 /t3IVYVpTDIPUGG6hTqDJzmSWXGhLFlfD3Ulei3/ycCnAqh5eCUxwp8LVqjtgltW mWqqZyIx+nafsW/YgWqyYu4p1wKR/O+x5hSbsWDiwfgJ876ZgyMeCYE/9cAqqb6x 3webtfId8ICVPIpXwkks2Hu0wlYrFIX5PUPtBjJZsb00DtuUbQKBwF5BfytRZ0Z/ 6ktTfHj1OJ93hJNF9iRGpRfbHNylriVRb+hjXR3LBk8tyMAqR4rZDzfBNfPip5en 4TBMg8UATf43dVm7nv4PM2e24CRCWXMXYl7G3lFsQF/g7JNUoyr6bZQBf3pQcBw4
  2. IJ38IcKV+L475tP4rfDrqyJz7mcJ+90a+ai5cSr9XoZqviAqNdhvBq5LjGOLkcdN bS0NAVVoGqjqIY/tOd2NMTEF6kVoYfJ7ZJtjxk/R3sdbdtajV3YsAg== -----END RSA PRIVATE KEY-----"""
  3. import paramiko from io import StringIO
  4. private_key = paramiko.RSAKey(file_obj=StringIO(key))
  5. # 创建SSH对象 ssh = paramiko.SSHClient()
  6. # 允许连接不在know_hosts文件中的主机 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  7. # 连接服务器
  8. ssh.connect(hostname='192.168.16.85', port=22, username='root', pkey=private_key)
  9. # 执行命令
  10. stdin, stdout, stderr = ssh.exec_command('df') # 获取命令结果
  11. result = stdout.read()
  12. # 关闭连接
  13. ssh.close()
  14. print(result)

生成

  1. 公司员工基于xshell连接服务器
  2. 用户名和密码 公钥和私钥(rsa

生成公钥和私钥

  1. ssh-keygen.exe -m pem
  2. 在当前用户家目录会生成:
  3. .ssh/id_rsa.pub .ssh/id_rsa

把公钥放到服务器

  1. ssh-copy-id -i ~.ssh/id_rsa.pub root@192.168.16.85

以后再连接服务器时,不需要在输入密码

  1. ssh root@192.168.16.85

总结

···

什么是前后端分离

  1. 固定知识返回json数据

drf组件

  1. 帮助我们在django框架基础上快速搭建遵循restful规范接口的程序

drf组件的功能

解析器,解析请求体中的数据,将其变成我们想要的格式.request.data

序列化 对对象或者对象列表(queryset)进行序列化 操作以及表单验证的功能

视图 继承APIView(在内部apiview继承了django的view)

postman

  1. 模拟浏览器进行发送请求

查找模板的顺序

  1. 优先根目录下的templates
  2. retframework 有一个templates
  3. 根据app的注册顺序去每个apptemplates目录中找

个人补充

  1. import uuid
  2. str(uuid.uuid4())#随机字符串
  3. models.表名.objects.all().none() 返回是一个none
  4. 添加数据库
  5. models.Disk.objects.create(**之后的字典,外键id=外键id)
  6. settings里面的基本都是用import importlib
  7. import importlib
  8. 利用字符串直接获得模块

登陆字段

  1. models.py
  2. inputblank=TRUE验证可以为空 null=True数据库可以为空 unique,唯一
  3. charfiled choice=sex_type(等于一个元组) id是值 名字是键 ((键,值),(键,值)) max_length=16
  4. verbose_name=’QQ昵称‘ label一样 显示作用于admin可以不写
  5. models.forekey('self')自关联
  6. multiselectField'咨询')需要第三方模块下载 多选下拉框
  7. verbose_name='客户信息表' admin创建表的时候的表名显示的数据
  8. unique_together=联合唯一 下载第三方模块 djangoMultiSelectField course = MultiSelectField("咨询课程", choices=course_choices) #多选,并且存成一个 列表的格式,通过modelform来用的时候,会成为一个多选框

水平分表

  1. 把数据比较多的平行分成两个表(分出来一个详细表)

mysqldb

  1. mysqldb是一个接口连接到mysql数据库服务器

request是什么

  1. #请求报文 由客户端发送,其中包含和许多的信息,而 django 将这些信息封装成了 HttpRequest 对 象,
  2. 请求报文 由客户端发送,其中包含和许多的信息,而 django 将这些信息封装成了HttpRequest 对象
  3. 1.该对象由 HttpRequest 祖类创建。
  4. 这个是wsgi是从属于类
  5. 2.每一个请求都会生成一个 HttpRequest 对象,
  6. 3.django会将这个对象自动传递给响应的视图函数,
  7. 4.视图函数第一个参数传给视图函数。这个参数就是django视图函数的第一个参数,通常写成request
  8. 5.一般视图函数约定俗成地使用 request 参数承接这个对象

表删除

  1. book_obj= 第一种 book_obj.objects.remove(1) 第二种 clear 清空 第三种 set(['1','5'])
  2. # 先清除再添加,相当于修改
  3. #把原来的删除重新添加进去,注意不是原位置

Form所有内置字段

  1. Field
  2. required=True, 是否允许为空
  3. widget=None, HTML插件
  4. label=None, 用于生成Label标签或显示内容
  5. initial=None, 初始值
  6. help_text='', 帮助信息(在标签旁边显示)
  7. error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
  8. validators=[], 自定义验证规则
  9. localize=False, 是否支持本地化
  10. disabled=False, 是否可以编辑
  11. label_suffix=None Label内容后缀
  12. CharField(Field)
  13. max_length=None, 最大长度
  14. min_length=None, 最小长度
  15. strip=True 是否移除用户输入空白
  16. IntegerField(Field)
  17. max_value=None, 最大值
  18. min_value=None, 最小值
  19. FloatField(IntegerField)
  20. ...
  21. DecimalField(IntegerField)
  22. max_value=None, 最大值
  23. min_value=None, 最小值
  24. max_digits=None, 总长度
  25. decimal_places=None, 小数位长度
  26. BaseTemporalField(Field)
  27. input_formats=None 时间格式化
  28. DateField(BaseTemporalField) 格式:2015-09-01
  29. TimeField(BaseTemporalField) 格式:11:12
  30. DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
  31. DurationField(Field) 时间间隔:%d %H:%M:%S.%f
  32. ...
  33. RegexField(CharField)
  34. regex, 自定制正则表达式
  35. max_length=None, 最大长度
  36. min_length=None, 最小长度
  37. error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
  38. EmailField(CharField)
  39. ...
  40. FileField(Field)
  41. allow_empty_file=False 是否允许空文件
  42. ImageField(FileField)
  43. ...
  44. 注:需要PIL模块,pip3 install Pillow
  45. 以上两个字典使用时,需要注意两点:
  46. - form表单中 enctype="multipart/form-data"
  47. - view函数中 obj = MyForm(request.POST, request.FILES)
  48. URLField(Field)
  49. ...
  50. BooleanField(Field)
  51. ...
  52. NullBooleanField(BooleanField)
  53. ...
  54. ChoiceField(Field)
  55. ...
  56. choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
  57. required=True, 是否必填
  58. widget=None, 插件,默认select插件
  59. label=None, Label内容
  60. initial=None, 初始值
  61. help_text='', 帮助提示
  62. ModelChoiceField(ChoiceField)
  63. ... django.forms.models.ModelChoiceField
  64. queryset, # 查询数据库中的数据
  65. empty_label="---------", # 默认空显示内容
  66. to_field_name=None, # HTML中value的值对应的字段
  67. limit_choices_to=None # ModelForm中对queryset二次筛选
  68. ModelMultipleChoiceField(ModelChoiceField)
  69. ... django.forms.models.ModelMultipleChoiceField
  70. TypedChoiceField(ChoiceField)
  71. coerce = lambda val: val 对选中的值进行一次转换
  72. empty_value= '' 空值的默认值
  73. MultipleChoiceField(ChoiceField)
  74. ...
  75. TypedMultipleChoiceField(MultipleChoiceField)
  76. coerce = lambda val: val 对选中的每一个值进行一次转换
  77. empty_value= '' 空值的默认值
  78. ComboField(Field)
  79. fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
  80. fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
  81. MultiValueField(Field)
  82. PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
  83. SplitDateTimeField(MultiValueField)
  84. input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
  85. input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
  86. FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
  87. path, 文件夹路径
  88. match=None, 正则匹配
  89. recursive=False, 递归下面的文件夹
  90. allow_files=True, 允许文件
  91. allow_folders=False, 允许文件夹
  92. required=True,
  93. widget=None,
  94. label=None,
  95. initial=None,
  96. help_text=''
  97. GenericIPAddressField
  98. protocol='both', both,ipv4,ipv6支持的IP格式
  99. unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1 PSprotocol必须为both才能启用
  100. SlugField(CharField) 数字,字母,下划线,减号(连字符)
  101. ...
  102. UUIDField(CharField) uuid类型

ajax补充

  1. traditional:true,
  2. ajax设置该属性就可以往后端传递数组

拓展性知识

ajax的traditional属性

  1. ajaxtraditional属性
  2. jquery框架的ajax参数除了常用的
  3. $.ajax({
  4. url: 'xxx',
  5. type: 'xxx',
  6. data: 'xxx',
  7. success: 'xxx'
  8. ...
  9. })
  10. 另外还有一个参数需要特别注意下traditional默认值是false
  11. ajax做数据处理时,是通过jQuery.param( obj, traditional )该方法进行处理。
  12. jquery1.4版本以后
  13. traditional参数,默认false的时候如果是{a:{b:'value'}}是处理成a[b],这样形式,如果是数组:data:{a:[1,2]},是解析成a[]=1&a[]=2,这种方式后台确实要做兼容(取a[b]或a[])来取值。
  14. 在数组情况下把traditional参数设置成true,是解析成a=1&a=2,对后台直接通过a拿数据。但是实验了下object情况,把traditional设置成true,转成了a=[object+Object],这样就是费的了。false时解析成上面的形式应该就是类型指示作用,我看到这种格式就知道请求数据是Array还是object了,true就是按照form提交的方式传值。
  15. 当需要把多个checkboxvalue值通过ajax传到servlet时就需要加上traditional参数并且为true,如下代码:
  16. //批量删除
  17. $("#alldel").click(function () {
  18. var ids = $(".che:checked");
  19. var items = new Array();
  20. for (var i=0;i<ids.size();i++){
  21. items.push(ids[i].value);
  22. }
  23. if (confirm("您确定要删除选中数据吗?")) {
  24. $.ajax({
  25. type: "post",
  26. url: "UserServlet?action=deleteAll",
  27. data:{items:items},
  28.                //防止深度序列化
  29. traditional :true,
  30. async: true,
  31. success: function(data) {
  32. var da = JSON.parse(data);
  33. alert(da.msg)
  34. app.count();
  35. },
  36. error: function(data) {
  37. console.info("error: " + data.responseText);
  38. }
  39. });
  40. }
  41. });

  1. 在后台我们就可以用 String[] items = request.getParameterValues("items") 进行接收前端传过来的数组,如下图:
  2. request.POST.get() #获取值
  3. 这样就可以用SQL语句 delete from xxx where id in(x,x) 多参数的形式进行操作了。

表结构很少有一对一之间的关系

很多时候都是1对多 多对多之间的关系

input 消除自动记忆功能

  1. html里就可以直接清除了<input type="text" autocomplete="off"> input autocomplete属性默认是on:其含义代表是否让浏览器自动记录之前输入的值 off:则关闭记录

查询多个用反向查询set

  1. # 多对多
  2. 如果post请求多个值使用getlist(字段)
  3. 写法
  4. obj=request.POST.getlist("author_id")
  5. #取得的是一个列表
  6. # 海狗的怂逼人生 是哪些作者写的 -- 正向查询
  7. obj = models.Book.objects.filter(title='海狗的怂逼人生').first()
  8. ret = obj.authors.all()#可以直接查询到作者对应的名字 (直接查询到)
  9. print(ret) #<QuerySet [<Author: 王洋>, <Author: 海狗>]>
  10. for i in ret:
  11. print(i.name)
  12. # 查询一下海狗写了哪些书 -- 反向查询
  13. obj = models.Author.objects.filter(name='海狗').first()
  14. ret = obj.book_set.all()
  15. print(ret)
  16. for i in ret:
  17. print(i.publishs.name)
  18. print(i.title)
  19. return HttpResponse('ok')

1.filter双下方法

  1. 1.2i不区分大小写

2.下拉框(select)选择出来的就是列表

  1. 如果post请求多个值使用getlist(字段) 写法 obj=request.POST.getlist("author_id") #取得的是一个列表

request.Get.get()取到的值是 ?后面对应

  1. 此写法的好处不需要添加多余的路径 不用分组路径 127.0.0.1/homeid=3 request.post.get()取到值是3

mysqldb是什么

  1. mysqldb是一个接口连接到mysql数据库服务器从python

wsgiref

  1. from wsgiref.simple_server import make_server
  2. # wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的 socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便) #函数名字随便起
  3. def application(environ, start_response):
  4. '''
  5. :param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多 你想要拿到的信息
  6. :param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数
  7. :return:
  8. '''
  9. start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')])
  10. print(environ)
  11. print(environ['PATH_INFO'])
  12. #输入地址127.0.0.1:8000,这个打印的是'/',输入的是 127.0.0.1:8000/index,打印结果是'/index'
  13. return [b'<h1>Hello, web!</h1>']
  14. #和咱们学的socketserver那个模块很像啊
  15. httpd = make_server('127.0.0.1', 8080, application)
  16. print('Serving HTTP on port 8080...')
  17. # 开始监听HTTP请求: httpd.serve_forever()#send application的返回值 一个列表

requset是什么

  1. #请求报文 由客户端发送,其中包含和许多的信息,而 django 将这些信息封装成了 HttpRequest 对 象,
  2. 请求报文 由客户端发送,其中包含和许多的信息,而 django 将这些信息封装成了HttpRequest 对象
  3. 1.该对象由 HttpRequest 祖类创建。
  4. 这个是wsgi是从属于类
  5. 2.每一个请求都会生成一个 HttpRequest 对象,
  6. 3.django会将这个对象自动传递给响应的视图函数,
  7. 4.视图函数第一个参数传给视图函数。这个参数就是django视图函数的第一个参数,通常写成request
  8. 5.一般视图函数约定俗成地使用 request 参数承接这个对象

示例

  1. print(requset) <WSGIRequest: GET '/app01/library/'>

表删除

  1. book_obj= 第一种 book_obj.objects.remove(1)
  2. 第二种 clear 清空
  3. 第三种 set(['1','5']) # 先清除再添加,相当于修改 #把原来的删除重新添加进去,注意不是原位置

知识点补充

bootstrapSweetAlert插件

  1. $(".btn-danger").on("click", function() {
  2. swal({
  3. title: "你确定要删除吗?",
  4. text: "删除可就找不回来了哦!",
  5. #标签显示的 type: "warning",
  6. showCancelButton: true,
  7. confirmButtonClass: "btn-danger",
  8. confirmButtonText: "删除",
  9. cancelButtonText: "取消",
  10. closeOnConfirm: false
  11. }, function() { #
  12. 注意当前的this是指谁调用了这个
  13. var deleteId = $(this).parent().parent().attr("data_id");
  14. $.ajax({
  15. url: "/delete_book/",
  16. type: "post",
  17. data: {
  18. "id": deleteId
  19. },
  20. success: function(data) {
  21. if (data.status === 1) {
  22. swal("删除成功!", "你可以准备跑路了!", "success");
  23. } else {
  24. swal("删除失败", "你可以再尝试一下!", "error")
  25. }
  26. }
  27. })
  28. });
  29. })

装饰器的补充

  1. falask路由会用 装饰器的原理 开放封闭原则 在不改变原函数代码的前提下, 在函数前函数后增加新的功能 手写简单装饰器
  2. def wrapper(f):
  3. def inner( * args, ** kwargs):
  4. return f( * args, ** kwargs)
  5. return inner
  6. 补充:
  7. import functools
  8. def wrapper(f):
  9. @functools.wraps(f)
  10. # 加了之后保留函数元数据( 名字和注释)
  11. def inner(*args,**kwargs):
  12. return f(*args,**kwargs)
  13. return inner
  14. '''
  15. 1.执行wrapper
  16. 2.返回inner重新赋值index
  17. '''
  18. index=wrapper(index)
  19. @wrapper
  20. def index(a1, a2):
  21. return a1+a2
  22. print(index.__name__) #查看函数名
  23. print(index.__doc__) #查看注释
  24. 1.不加内部装饰器functools.wraps index执行的是inner 2.加了保留函数元数据(名字和注释)

orm补充

  1. verbose_name#admin显示的名字
  2. 以后在model form form中使用
  3. 写法
  4. name=models.CharField(verbose_name="出版社名称",max_length=32)

路由系统中记得加入终止符$

  1. 这种写法的好处: 防止/index/下的子页面访问路径被之前路径的匹配
  2. urls.py路由中写法 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/$',views.index)
  3. ]

模板查找顺序

  1. 1.先从根目录去找templates
  2. 2.在根据app注册顺序去每个apptemplates中找(从上往下)

drf的更多相关文章

  1. DRF如何序列化外键的字段

    我觉得在有些应用场景下,这个操作是有用的,因为可以减少一个AJAX的请求,以增加性能. 当然,是二次请求,还是一次传输.这即要考虑用户体验,还要兼顾服务器性能. 一切是有条件的平衡吧.就算是一次传输, ...

  2. DRF限制访问频次

    官方文档:https://www.django-rest-framework.org/api-guide/throttling/ 1.什么场景下需要限制访问频次呢? 1)防爬虫:爬虫可能会在短时间内大 ...

  3. DRF缓存

    对于现在的动态网站来讲,所有的界面展示都是通过客户端请求服务端,服务端再去请求数据库,然后将请求到的数据渲染后返回给客户端.用户每次访问页面都需要去请求数据库,如果同时有多个人访问的话,对于我们的数据 ...

  4. drf相关问题

    drf自定义用户认证: 登录默认 使用django的ModelBackend,对用户名和密码进行验证.但我们平时登录网站时除了用户名也可以用邮箱或手机进行登录,这就需要我们自己扩展backend 一. ...

  5. DRF 缓存解决方案 drf-extensions / redis

    drf-extensions 概述 drf-extensions组件内部提供了 DRF  的本地内存方式的缓存方式 本地内存方式缓存在项目重启后则会消失 官方点击 这里 安装 pip3 install ...

  6. DRF 商城项目 - 用户( 登录, 注册,登出,个人中心 ) 逻辑梳理

    用户登录 自定义用户登录字段处理 用户的登录时通过 手机号也可以进行登录 需要重写登录验证逻辑 from django.contrib.auth.backends import ModelBacken ...

  7. luffy项目后台drf搭建(1)

    一 进入虚拟环境 打开crm,输入命令 workon luffy 虚拟环境使用文档 二 安装基本类库 pip install django pip install PymySQL pip instal ...

  8. DRF项目创建流程(1)

    一 web应用模式 前后端不分离 前后端分离 二 RESTFUL API规范 REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态 ...

  9. DRF初识与序列化

    一.Django的序列化方法 1.为什么要用序列化组件 做前后端分离的项目,我们前后端数据交互一般都选择JSON,JSON是一个轻量级的数据交互格式.那么我们给前端数据的时候都要转成json格式,那就 ...

  10. restfull规范、DRF视图和路由

    一.restfull规范的简单介绍 1.介绍 REST:表述性状态转移,是一种web交互方案 资源:在web中只要有被引用的必要都是资源 URI: URI 统一资源标识符 URL 统一资源定位符 统一 ...

随机推荐

  1. JVM垃圾回收(下)

    接着上一篇,介绍完了 JVM 中识别需要回收的垃圾对象之后,这一篇我们来说说 JVM 是如何进行垃圾回收. 首先要在这里介绍一下80/20 法则: 约仅有20%的变因操纵着80%的局面.也就是说:所有 ...

  2. 模块的 __name__

    模块的 __name__ 每个模块都有一个名称,而模块中的语句可以找到它们所处的模块的名称.这对于确定模块是独立运行的还是被导入进来运行的这一特定目的来说大为有用.正如先前所提到的,当模块第一次被导入 ...

  3. vue中methods,computed,filters,watch的总结

    08.28自我总结 vue中methods,computed,filters,watch的总结 一.methods methods属性里面的方法会在数据发生变化的时候你,只要引用了此里面分方法,方法就 ...

  4. JavaScript回调函数和递归函数

    一.回调函数--通过函数的指针来调用函数 把一个函数的指针作为另一个函数的参数,当调用这个参数的时候,这个函数就叫做回调函数 在链式运动上会用到回调函数,之后运动会见到 A.通过指针来调用函数 B.通 ...

  5. Elastic Stack 简介

    一.ElasticSearch ElasticSearch 是一个基于 Apache Lucene 的开源搜索引擎.它通过RESTful API 来隐藏Lucene的复杂性,从而让全文搜索变得简单.不 ...

  6. Topaz ReMask 5抠图神器

    Topaz ReMask 5抠图神器 与Photoshop相比,ReMask不需要繁琐的刷子工作来获得高质量的面膜.您只需粗略勾勒出主题并按"计算"即可. 在Photoshop中制 ...

  7. jenkins pipeline 流水线生产

    jenkins pipeline : pipeline { agent any parameters { string(name: 'git_version', defaultValue: 'v1.1 ...

  8. 非确定的自动机NFA确定化为DFA

    摘要: 在编译系统中,词法分析阶段是整个编译系统的基础.对于单词的识别,有限自动机FA是一种十分有效的工具.有限自动机由其映射f是否为单值而分为确定的有限自动机DFA和非确定的有限自动机NFA.在非确 ...

  9. 思科Cisco 交换机 VTP负载均衡的配置

    思科Cisco 交换机 VTP负载均衡的配置 3560三层交换机配置: int ran fa0/23 - fa0/24 sw trunk encapsolution dot1q sw mode tru ...

  10. Java11新特性 - Epsilon GC和ZGC

    Java11中新增了两个GC,Epsilon GC和ZGC. Epsilon垃圾收集器 A NoOp Garbage Collector 没有操作的垃圾收集器 JDK上对这个特性的描述是:开发一个处理 ...