Django是一个优秀的Python web框架,被众多python开发者所喜爱。新开这个Django专栏,并不是从零开始详细使用Django框架来开发web网页,而是用来开发api。前后分离是当前的技术栈潮流

1.API频率限制
2.models模型中的过滤器详解
3.APPEND_SLASH路由设置
4.drf的三大认证(认证,权限,频率)

1.API频率限制

当我们使用api时,为了应对一些爬虫,往往会对api接口访问频率进行限制,官方文档

官方是给出两种方法:用户自定义访问频率,官方给定的访问频率

  1. 通用访问频率:drf框架下的throttle
    在主settings.py中设置访问频率,但通用访问频率一旦设置,每一个使用官方其配置的api接口都必须遵守这个通用访问频率
  • throttle配置到settings.py中
1
2
3
4
5
6
7
8
9
10
11
12
# REST_FRAMEWORK配置文件
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '3/minute', # 未认证用户每分钟访问次数       
'user': '10/minute', # 认证用户每分钟访问次数
'limit': '5/minute' # 自定义的访问频率
}
}

The rate descriptions used in DEFAULT_THROTTLE_RATES may include second, minute, hour or day as the throttle period.

限制规则与限速的类。未登录情况下限速,通过IP地址;登录情况下通过session或token来判断

  • 设置到视图views.py中的接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
# throttle_classes = [UserRateThrottle] # 限制登录用户的访问频率
throttle_classes = [AnonRateThrottle] # 限制匿名用户访问频率
# throttle_classes = [] # 空列表表示不限制任何用户的访问频率

def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)

2.models模型中的过滤器详解

官方文档:QuerySet API reference

查询集:表示从数据库获取的对象集合,查询集可以有多个过滤器,过滤器就是一个函数(方法),基于所给参数限制查询集结果
从sql角度来说,查询集和select等价,过滤器和where等价.

查询集特点:

  • 惰性执行:创建查询集不会带来任何的数据访问,直到调用数据(要用滴时候)时,才会访问数据

  • 直接访问数据的情况(直接向数据库拿):迭代/序列化/与if合用

返回查询集的方法称为过滤器

我们很少会一次性从数据库中取出所有的数据;通常都只针对一部分数据进行操作。 在Django API中,我们可以使用filter() 方法对数据进行过滤,类似于SQL中的where查询条件

返回一堆数据集的过滤器

方法 说明
.all() 返回查询集中的所有的对象(形如Publisher.objects.all())
.filter() 返回符合条件的数据集,相当于where
.order_by() 排序
.row(sql) 执行原生查询
.values() 返回查询集中具体的字段名,(Category.objects.all().values(‘id’, ‘name’)
就表示返回Category表的id,name字段)

PS:关于对.values()的说明:
values()并不是像sql里的select field1,field2,…一样可以自由选择目标字段。它受制于序列化函数中的fields属性,values()中的目标字段必须是跟序列化中的fields字段完全相同,不能多,但也不能少。
若values()的字段选择有多种,同理的serializers也要定义多种情况

1
2
3
4
5
serializers序列化中的fields表示要展示的字段,有两种写法:
写法一:
fields = "__all__":表示全部展示Category模型里的所有字段
写法二:
fields = ['id','name',...]:将想要展示的Category模型里的特定字段添加到数组中

返回单行数据的过滤器

方法 说明
.get() 返回一个满足条件的对象
.count() 返回当前查询集的对象个数
.first() 返回查询集的第一个对象
.last() 返回查询集的最后一个对象
.exists() 判断查询集中是否有数据,若有数据返回True

字段查询

概述:实现类sql中where语句,作为方法filter(),exclude(),get()的参数
语法:属性名称__比较运算符 = 值
外键:属性名_id

详细请查阅:https://www.cnblogs.com/vera-y/p/11918071.html

举例阐述:models.py模型自定义一个名为Publisher的类

1
2
3
4
# 传递单个参数到 filter() 来确定选取范围
Publisher.objects.filter(name='Apress')
# 传递多个参数到 filter() 来缩小选取范围
Publisher.objects.filter(country="U.S.A.", state_province="CA")

filter() 根据关键字参数来转换成 WHERE SQL语句。 前面这个例子 相当于这样:

1
2
3
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress'

这样我们就可以明朗起来的,通过传递多个参数到filter(),来缩小选取范围


order_by 排序

字段前面加 - 号前缀,表示为desc倒序

1
2
3
4
5
Articlelist = Article.objects.filter(**kwargs).order_by('nid')
Articlelist = Article.objects.filter(**kwargs).order_by('-nid') #倒序
Articlelist = Article.objects.order_by('-nid') # 当查询方法为all时的简写
可以使用两个字段进行排序:用在第一个字段相等,用第二个来排序的情形
Articlelist = Article.objects.order_by('-nid','ctime')

注意:字符型字段是按照ascii码来排序的,而数值型是按照数值来排序的


.row(sql)执行原生sql查询

使用row来执行原生的sql查询,会有很多额外选项,代码更加灵活强大,但也要避免 SQL 注入

1
2
3
4
5
6
7
Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')

Person.objects.raw('''SELECT first AS first_name,
... last AS last_name,
... bd AS birth_date,
... pk AS id,
... FROM some_other_table''')

注意:无论何时编写原生 SQL 都要万分小心。使用时,你要用 params 将任何用户传入的参数进行安全转义,避免 SQL 注入攻击。阅读 SQL 注入保护 了解更多。

3.APPEND_SLASH路由设置

问题出现原因:发送请求时,提交表单报错:RuntimeError: You called this URL via POST, but the URL doesn’t end in a slash and you have APPEND_SLASH set.

出现这个问题主要是因为:
在主urls.py中,注意下列这两个路由结尾是否存在斜杆

1
2
3
4
5
6
from django.urls import path, re_path
from . import views # 导入views文件中的视图函数(标准写法)
urlpatterns = [
path('order', views.OrderView.as_view()),
path('user/', views.UserView.as_view()),
]
  • 当路由结尾不存在斜杠时:
    修改settings:APPEND_SLASH=False,此时访问路由时,有没有斜杠都没有关系
  • 当路由结尾存在斜杠时:
    修改settings:APPEND_SLASH=True,此时访问路由时,有没有斜杠都没有关系

路由设置举例:

1
2
3
4
5
# 哔哩哔哩个人主页
path("bilibili/", views.BIli.as_view()),

settings.py:
APPEND_SLASH = True

4.DRF的三大认证

4.1 认证

我们的某些接口需要对用户进行辨别,那么我们该如何区分A用户和B用户呢?如果A用户想访问B用户的余额,这种操作是不被允许的。在django中,已经完成过基于cookie和session的身份认证,对登录的用户返回一个cookie,并在服务端也进行保存,用户必须携带cookie才能通过用户认证。

drf的认证规则:

  • 如果没有认证信息,则认为是游客
  • 如果认证失败,抛出异常
  • 认证成功返回(user,token)
    • 正义
    • 活着

rest_framework文件下的authentication.py中为我们写好了用户认证的基类,及一些基础的认证类。我们可以通过重写authenticate和相关的方法来定义自己的用户认证类。

DRF登录认证组件

  1. 写一个登录认证类(类名随意,类中的方法名固定)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from . import models
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication


class Auth(BaseAuthentication):

def authenticate(self,request):
token = request.query_params.get('token')
res = models.Token.objects.filter(token=token).first()
if res:
#放回的res.user就是将user添加到request中user中,res会添加到request的auth中
return res.user,res
# return None, None
else:
raise exceptions.APIException('您还没有登录!')

参考文章


 评论

联系我 | Contact with me

Copyright © 2019-2020 谁知你知我,我知你知深。此恨经年深,比情度日久

博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议