在完成了登录和注册视图之后,需求中还需要管理员可以管理用户列表,所以就需要完成基础的增删改查操作
在注册和登录操作中,我们的API对谁可以编辑或删除项目没有任何限制。我们希望有一些更高级的行为,以确保:
身份验证是将传入请求与一组识别凭证相关联的机制,例如请求携带的用户名密码,签名令牌等。然后权限之类的限制策略才可以使用这些凭证来确定是否应该允许请求。
身份验证始终在视图的最开始运行,在权限和限制检查发生之前,在任何其他代码被允许继续之前。
REST框架提供多种开箱即用的身份验证方案,后面项目实战时,我们再讨论。
与身份验证,限流一起,权限决定是否应该授予或拒绝访问请求。
权限检查总是在视图的最开始运行,在任何其他代码被允许继续之前。权限检查通常会使用request.user
和request.auth
属性中的身份验证信息来确定是否应允许传入请求。
权限用于授予或拒绝不同类别的用户访问 API 的不同部分。
最简单的权限样式是允许任何经过身份验证的用户访问,而拒绝任何未经身份验证的用户访问。
DRF中权限始终定义为权限列表。在运行视图的主体之前,检查列表中的每个权限。如果任何权限检查失败,将引发exceptions.PermissionDenied
orexceptions.NotAuthenticated
异常,并且视图的主体将不会运行。当权限检查失败时,将根据以下规则返回“403 Forbidden”或“401 Unauthorized”响应:
WWW-Authenticate
标头。— 将返回 HTTP 403 Forbidden 响应。可以使用设置全局设置默认权限策略DEFAULT_PERMISSION_CLASSES
。例如。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
如果未指定,此设置默认为允许不受限制的访问:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
您还可以使用基于APIView类的视图,在每个视图或每个视图集的基础上设置权限策略
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
或者使用基于装饰器@api_view
的函数视图
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
pass
注意:直接在视图上设置权限类列表后,会忽略设置文件中配置的权限类列表。
进行增删改查操作起码需要用户是已完成登录的
from rest_framework.permissions import IsAuthenticated
permission_classes = [IsAuthenticated]
这次使用的是IsAuthenticated
Allows access only to authenticated users. 仅允许对经过身份验证的用户进行访问。
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
对于大量数据的传输需要进行分页操作。
REST framework已经实现了分页api。它支持:
Content-Range
或Link
。注意只有在使用通用视图或视图集时,分页才会自动执行。如果你使用一个常规的APIView,你需要自己调用分页API来确保你返回一个分页的响应。
REST framework中可以对分页功能进行settings.py全局设置,例如:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE':
}
注意,您需要同时设置DEFAULT_PAGINATION_CLASS
和PAGE_SIZE
,它们的默认值都为None,表示不使用分页。
还可以使用pagination_class属性在单个视图上设置分页类。
如果希望修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
class LargeResultsSetPagination(PageNumberPagination):
page_size =
page_size_query_param = 'page_size'
max_page_size =
class StandardResultsSetPagination(PageNumberPagination):
page_size =
page_size_query_param = 'page_size'
max_page_size =
然后你可以使用pagination_class
属性将你的新样式应用到视图中:
class BillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer_class = BillingRecordsSerializer
pagination_class = LargeResultsSetPagination
当然也可以进行全局配置。settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
这是一个简单的页码的分页类。
请求案例
GET https://api.example.org/accounts/?page=4
响应
HTTP 200 OK
{
"count": 1023
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
同分页设置一样,settings.py全局使用配置如下:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE':
}
在GenericAPIView
的子类通过在每个视图中设置pagination_class
属性来应用分类。
可以像上面一样复写下面的属性,来修改分类样式。
django_paginator_class
- django框架分页类。默认使用django.core.paginator.Paginator
。page_size
- 表示一页数据条数的数值。如果设置会覆盖设置中的PAGE_SIZE
。page_query_param
- 一个字符串参数名,表示查询的页码,默认是page
。page_size_query_param
- 一个字符串参数名,表示查询的每页数据数量。默认为None
表示不能过客户端控制每页数据量。max_page_size
- 每页的最大数据量,和page_size_query_param
配合使用。这种分页样式使用了在查找多个数据库记录时使用的语法。客户端包含一个limit
和一个offset
查询参数。limit
表示要返回的最大项数,与其他样式中的page_size
相同。offset
表示查询相对于完整的未分页项集的起始位置。
请求
GET https://api.example.org/accounts/?limit=100&offset=400
响应
HTTP 200 OK
{
"count": 1023
"next": "https://api.example.org/accounts/?limit=100&offset=500",
"previous": "https://api.example.org/accounts/?limit=100&offset=300",
"results": [
…
]
}
同分页设置一样,全局使用配置如下:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE':
}
在GenericAPIView
的子类中通过在每个视图中设置pagination_class
属性来应用分类。
可以像上面一样复写下面的属性,来修改分类样式。
default_limit
- 一个数字值,表示客户端在查询参数中未提供limit
时所使用的值。默认值与PAGE_SIZE
设置键相同。limit_query_param
- 一个字符串,表示limit
参数的参数名,默认为limit
offset_query_param
- 一个字符串,表示offset
参数的参数名,默认为offset
max_limit
- 如果设置,这是一个数字,表示最大允许客户端请求的limit
,默认为None
需要根据前端来定制一下分页方式
打开前端查看前端的分页请求
前端路由:http://localhost:2800/#/template/list/crud
请求方式:GET
请求地址:http://localhost:2800/api/demo/list?page=1&pageSize=20&_=1661078091156
请求参数:
page: 1
pageSize: 20
_: 1661078091156
响应内容:
{
"code": ,
"data": {
"total": ,
"page": ,
"pageSize": ,
"summary": {
"num": "999.00",
"progress": "888.00"
},
"rows": [
{
"id": "21000020120129734X",
"name": "Michael Anderson",
"email": "y.dbmfuhlk@hydi.cf",
"ip": "93.210.85.155",
"datetime": "2015-02-22 19:07:01",
"boolean": true,
"type": "0",
"sex": "女",
"progress": ,
"num":
},
...
]
},
"message": ""
}
从这里可以看出几个内容
pageSize
{
"code": ,
"data": {
"total": ,
"page": ,
"pageSize": ,
"rows": []
},
"message": ""
}
自定义一个自己的分页backend/utils/pagination.py
class TenItemPerPagePagination(PageNumberPagination):
page_size =
page_size_query_param = 'pageSize'
max_page_size =
def get_paginated_response(self, data):
return Response(OrderedDict([
('data', OrderedDict([
('page', self.page.paginator.num_pages),
('pageSize', self.page.paginator.per_page),
('rows', data),
('total', self.page.paginator.count)
])),
('message', ""),
('code', ),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
]))
page_size_query_param
设置为新的分页请求名称pageSize
get_paginated_response
处理的是分页的返回信息,将信息重新组织一下按照前端的方式返回
把几个东西组合一下
class UserViewSet(ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all().order_by('-date_joined') # 按创建时间倒序
permission_classes = [IsAuthenticated]
pagination_class = TenItemPerPagePagination
这个视图中包含了增删改查几个接口
它的路由也是由drf封装好了
使用DefaultRouter
就可以一次性完成这几个接口
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('', views.UserViewSet)
urlpatterns = [
...
path('', include(router.urls))
]
运行后台项目,打开http://127.0.0.1:8000/users/
这表示我们的权限控制生效了
为了让他不返还「身份认证信息未提供」,需要先登录
登录之前需要先注册,访问之前的注册接口:http://127.0.0.1:8000/users/register/
填写信息后点击POST
访问登录接口:http://127.0.0.1:8000/users/login/
输入账号密码后点击POST
使用Postman 携带这个token
去请求用户列表地址:http://127.0.0.1:8000/users/
GET请求:http://127.0.0.1:8000/users/
POST请求(无参数):http://127.0.0.1:8000/users/
POST请求(有参数):http://127.0.0.1:8000/users/
PATCH请求(局部更新):http://127.0.0.1:8000/users/1/
DELETE请求:http://127.0.0.1:8000/users/2/