第四部分的学习主要是关于API的权限的,目前,我们的API对谁可以编辑或删除代码段没有任何限制。我们希望有更高级的行为,以确保:
(1) 代码片段始终与创建者相关联。
(2) 只有通过身份验证的用户可以创建片段。
(3) 只有代码片段的创建者可以更新或删除它。
(4) 未经身份验证的请求应具有完全只读访问权限。
1.往我们的模型中加入一些信息
//编辑snippets/models.py文件,加入以下两个字段 #其中,owner用来存储创建snippet的用户,另一个则用来存储高亮的HTML内容 owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE) highlighted = models.TextField() //我们还需要用到pygments,使用它来填充要高亮显示的字段 //首先导入以下依赖包 from pygments.lexers import get_lexer_by_name from pygments.formatters.html import HtmlFormatter from pygments import highlight //然后加入一个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) //清空之前的数据库,重新进行数据库迁移操作 python manage.py makemigrations snippets python manage.py migrate //创建几个用户 python manage.py createsuperuser
2.给用户模型增加路径
在snippets/serializers.py中,创建一个新的序列化器 //首先导入依赖包 from django.contrib.auth.models import User //创建一个序列化器UserSerializer class UserSerializer(serializers.ModelSerializer): snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all()) //你可能会疑惑为啥snippets为作为字段传进去,
//因为'snippets' 在用户模型中是一个反向关联关系。在使用 ModelSerializer 类时它默认不会被包含,所以我们需要为它添加一个显式字段 class Meta: model = User fields = ('id', 'username', 'snippets')
3.编写views.py
//在views.py中,我们希望仅对用户使用只读视图,所以我们使用ListAPIView和RetrieveAPIView这两个通用的基类视图 //首先导入以下依赖包 from snippets.serializers import UserSerializer 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
4.URL的编写
//将以下路径加入到snippets/urls.py当中 url(r'^users/$', views.UserList.as_view()), url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
5.将Snippet和用户关联
//在views.py中,将以下函数,添加到SnippetList当中 //目的是使序列化器的create()方法现在将被传递一个附加的'owner'字段以及来自请求的验证数据。 def perform_create(self, serializer): serializer.save(owner=self.request.user) //在serializers.py的SnippetSerializer中,添加这个字段 //ReadOnlyField类表示始终只是可读的,只能用于序列化展示,不能用于在反序列化中更新模型实例 owner = serializers.ReadOnlyField(source='owner.username') //别忘了还要把owner添加到Meta类中的fields中
6.添加视图所需要的权限
//我们要确保经过身份验证的请求才能获得读写访问权限,未经身份验证的请求将获得只读访问权限 //在views.py中,导入permissions from rest_framework import permissions //在SnippetList和SnippetDetail当中,添加这行代码: permission_classes = (permissions.IsAuthenticatedOrReadOnly,) //编辑tutorial.py,添加urlpatterns urlpatterns += [ url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), ]
7.创建对象级别的权限
//在snippets下,创建一个permissions.py文件,并写入以下内容 from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): """ 自定义权限只允许对象的所有者编辑它。 """ def has_object_permission(self, request, view, obj): # 读取权限允许任何请求, # 所以我们总是允许GET,HEAD或OPTIONS请求。 if request.method in permissions.SAFE_METHODS: return True # 只有该snippet的所有者才允许写权限。 return obj.owner == request.user //接下来,编辑views.py,导入IsOwnerOrReadOnly from snippets.permissions import IsOwnerOrReadOnly 在SnippetDetail的permission_classes中,加上IsOwnerOrReadOnly permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)
8.完结撒花
//接下来,你运行项目可能会报'CSRFCheck' object has no attribute 'process_request' 这个错误在settings.py中,加入以下代码即可,如没报错即可忽略。 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [] }