别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

    • Django 学习资料收集
    • Django-REST-framework教程中文版

      • Django-REST-framework 教程中文版
      • 快速入门
      • 教程 1:序列化
      • 教程 2:Requests 和 Responses
      • 教程 3:类视图
      • 教程 4:认证和权限
        • 向模型中新增字段
        • 为用户模型添加接口
        • 关联 user 和 snippet
        • 更新 serializer
        • 添加权限认证
        • 添加登录功能
        • 对象级别的权限
        • 为 API 调用添加认证信息
        • 总结
      • 教程 5:Relationships 和 Hyperlinked
      • 教程 6:ViewSets 和 Routers
  • stackoverflow

  • Flask

  • 全栈之路

  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • Django
  • Django-REST-framework教程中文版
佚名
2021-04-13
目录

教程 4:认证和权限

现在我们的 API 没有任何限制谁可以编辑删除代码片段,我们需要一些更好的功能来满足下列要求:

  • 代码片段需要和创建者进行关联
  • 只有认证用户可以创建新的代码片段
  • 只有创建者才能修改或删除代码片段
  • 未认证用户只有只读权限

# 向模型中新增字段

Snippet模型需要作出一些改变。首先添加 2 个字段,一个字段用于表明谁创建了这个代码片段,另一个用来存储高亮的 HTML 代码。

编辑models.py中关于Snippet的模型,新增下列代码:

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
1
2

也要确保当实例被保存时,使用pygments库来正确处理 highlighted 字段。

所以需要引入一些额外的包:

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
1
2
3

接下来,添加.save()到模型中:

def save(self, *args, **kwargs):
    """
    使用pygments来创建高亮的HTML代码。
    """
    lexer = get_lexer_by_name(self.language)
    linenos = self.linenos and 'table' or False
    options = self.title and {'title': self.title} or {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                                full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)
1
2
3
4
5
6
7
8
9
10
11

完成上面的步骤后,我们需要更新数据库表。正常情况下我们需要创建一个数据库迁移任务来实现这个目标,但在本教程中,我们删除整个数据库重新建表:

rm -f tmp.db db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
1
2
3
4

你也许还需要创建几个用户来测试 API,最简便的办法还是使用python manage.py createsuperuser命令。

python manage.py createsuperuser
1

# 为用户模型添加接口

现在我们有一些用户了,我们最好在 API 中添加些用户相关的接口。修改serializers.py并添加下列代码:

from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ('id', 'username', 'snippets')
1
2
3
4
5
6
7
8

因为 'snippets' 和用户是一种反向关联,默认情况下不会包含在ModelSerializer类中,所以我们需要手动添加。

我们也需要对views.py进行修改,另外用户页面是只读的,所以使用ListAPIView以及 RetrieveAPIView这 2 个通用类视图:

from django.contrib.auth.models import User


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

1
2
3
4
5
6
7
8
9
10
11
12

确保引入了UserSerializer类:

from snippets.serializers import UserSerializer
1

最后还需要对其进行 URL 的配置,修改urls.py,添加下列代码:

path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
1
2

# 关联 user 和 snippet

现在,如果我们创建一个代码片段,是没法和用户进行关联的。因为用户信息是通过 request 获取而不是以 serialized 数据传递的。

为了解决这个问题。我们需要重写 snippet 视图中.perform_create()方法,这个方法准许我们修改实例如何被保存、处理任何由 request 或 requested URL 传递进来的隐含数据。

修改SnippetList,新增下列代码:

def perform_create(self, serializer):
    serializer.save(owner=self.request.user)
1
2

现在create()方法将获得一个新的字段'owner',值就是 request 中的用户信息。

# 更新 serializer

现在代码片段和创建者之间建立了联系,现在需要修改SnippetSerializer来反映这一变化。修改serializers.py添加下列代码:

owner = serializers.ReadOnlyField(source='owner.username')
1

提示

注意:确保你也添加了'owner'到内部类Meta中的 fields 字段里。

这个字段正在做一些非常有趣的事情。source参数控制哪个属性用于填充字段,并可以指向序列化实例上的任何属性。它也可以采用上面所示的点符号,在这种情况下,它将遍历给定的属性,与 Django 的模板语言使用的方式类似。

这里我们还使用了ReadOnlyField类型,不同于其他字段类型,比如CharField, BooleanField等。这种类型是只读的,用于进行序列化时候的展示,并且反序列化时不会被修改。这里我们也可以使用CharField(read_only=True)来替代它。

# 添加权限认证

现在我们将代码片段和用户进行了关联,但我们需要确保只有认证用户才能创建、修改、删除代码片段。

REST framework 包含了多种认证类,这里我们使用IsAuthenticatedOrReadOnly,这个类确保了只有认证用户才有读写权限,未认证用户则只有只读权限。

修改views.py,添加:

from rest_framework import permissions
1

然后修改SnippetList和SnippetDetail类,添加:

permission_classes = [permissions.IsAuthenticatedOrReadOnly]
1

# 添加登录功能

如果你现在打开浏览器,你会发现你无法创建新的代码片段了,所以我们需要启用用户登录功能。编辑tutorial/urls.py新增代码:

from django.conf.urls import include
1

在最后,添加:

urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]
1
2
3

你可以将'api-auth'替换成任何你喜欢的字符串,唯一的限制就是 namespace 必须为'rest_framework'。在 Django1.9+的版本中,REST framework 将自动设置,所以无需理会。

现在再次刷新页面将在右上角看到'Login'按钮,登录后就可以创建新代码片段了。

当你创建了几个代码片段后,访问/users/页面,就会看到每个用户对应的代码片段的主键列表了。

# 对象级别的权限

现在所有人都可以浏览代码片段了,接下来实现只有创建者才能删除或修改自己的代码片段功能。想实现这点,我们需要自定义权限认证方法。

新建文件permissions.py:

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    自定义权限,只有创建者才能编辑
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

接下来修改SnippetDetail视图:

permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly]
1
2

并确保引入了所需的类:

from snippets.permissions import IsOwnerOrReadOnly
1

再次打开浏览器,如果你是这个代码片段的创建者的话,你会看到'DELETE'和'PUT'操作按钮。

# 为 API 调用添加认证信息

因为我们添加了权限认证,所以我们想编辑任何代码片段时都需要提供认证信息。我们并没有设置任何认证相关的类,目前默认的认证方法是SessionAuthentication和BasicAuthentication。

当我们使用浏览器访问时,我们可以登录,浏览器会自动处理 session 信息用于认证。当我们使用编程方式调用 API 时,我们需要显式的为每个请求提供认证信息。

如果我们尝试创建一个代码片段而未提供认证消息的话,我们会得到一个错误返回:

http POST http://127.0.0.1:8000/snippets/ code="print 123"

{
    "detail": "Authentication credentials were not provided."
}
1
2
3
4
5

而提供用户名和密码就可以创建了:

http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"

{
    "id": 5,
    "owner": "tom",
    "title": "foo",
    "code": "print 789",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}
1
2
3
4
5
6
7
8
9
10
11

# 总结

现在,我们已经在 Web API 上获得了一组相当细粒度的权限,以及系统用户和他们创建的代码片段的端点。

在本教程的第 5 部分中,我们将了解如何通过为突出显示的代码片段创建 HTML 端点来将所有东西联系在一起,并通过为系统内的关系使用超链接来改进 API 的内聚性。

编辑 (opens new window)
#DRF
上次更新: 2024-07-23, 01:00:43
教程 3:类视图
教程 5:Relationships 和 Hyperlinked

← 教程 3:类视图 教程 5:Relationships 和 Hyperlinked→

最近更新
01
2025 面试记录
05-28
02
提升沟通亲和力的实用策略
03-26
03
工作
07-15
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式