python技术交流群332680349,资源分享,技术交流。
我们现在的API没有任何权限限制,任何人都可以编辑或者删除代码片段。
我们想要进行一些高级操作,以确保下列行为:
- 代码片段始终和创建者关联
- 只有身份验证过的用户可以创建代码片段
- 只有创建者可以更新或者删除
- 没有经过验证的请求只有只读权限
01-将信息添加到模型
我们将对我们的Snippet模型类进行几次更改。首先,我们添加关联字段。其中一个字段将用于表示创建代码段的用户。另一个字段将用于存储代码的高亮的HTML展示。
将以下两个字段添加到Snippet模型中models.py。
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):
"""
Use the `pygments` library to create a highlighted HTML
representation of the code snippet.
"""
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)
完成这些工作后,我们需要更新我们的数据库表。通常我们将创建一个数据库迁移,为了做到这一点,但为了本教程的目的,我们只需删除数据库并重新开始。
rm -f tmp.db db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate
您可能还需要创建几个不同的管理员用户,以用于测试API。执行此操作的最快方法是使用createsuperuser命令。
python manage.py createsuperuser
02-将端点添加到模型
现在我们有一些管理员用户可以使用,我们最好将这些用户的表示添加到我们的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')
因为’snippets’是用户模型的反向关系,当我们使用ModelSerializer该类时它不会被默认包含,所以我们需要为它添加一个显式字段。
我们还会添加关联视图在views.py。我们希望只使用只读视图为用户展示,所以我们将使用ListAPIView和RetrieveAPIView通用的基于类的视图。
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
要注意导入UserSerializer类
from snippets.serializers import UserSerializer
最后,我们需要通过从URL 配置引用它们,将这些视图添加到API中。将以下内容添加到urls.py。
url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()
03-用户关联代码片段
现在,如果我们创建了一个代码片段,那么就没有办法将创建该代码段的用户与代码段实例进行关联。用户不是作为序列化展示的一部分发送的,而是传入请求的属性。
我们处理的方式是用.perform_create()方法,在我们的代码片段视图上,这样我们可以修改实例保存的管理方式,并处理传入请求或请求的URL中隐含的任何信息。
在SnippetList视图类中,添加以下方法:
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
我们的串行器的create()方法现在将被传递一个附加’owner’字段,以及验证请求中的数据。
04-更新串行器
现在,这些片段与创建它们的用户相关联,我们更新我们SnippetSerializer来显示这一点。将以下字段添加到序列化器中,在serializers.py:
owner = serializers.ReadOnlyField(source='owner.username')
注意:确保您还添加’owner’,到内部Meta类的字段列表。
这个部分正在做一些很有趣的事情。source属性参数控制用于填充用户名字段,并且可以指向串行器实例对象的任何属性。它也可以采用上面的操作,在这种情况下,它将以与Django的模板语言一样的方式遍历给定的属性。
我们添加了只读字段属性,相对于其他类型的字段,如CharField,BooleanField等…类型化ReadOnlyField始终是只读的,并且将用于序列化查看形式(只读),但不会被用于更新模型他们被反序列化的实例。我们也可以CharField(read_only=True)在这里使用。
05-在视图添加请求权限
现在,代码片段与用户相关联,我们希望确保只有经过身份验证的用户才能创建,更新和删除代码段。
REST框架包括许多权限类,我们可以使用它来限制哪些人可以访问给定的视图。在这种情况下,我们需要的是IsAuthenticatedOrReadOnly这个属性,这将确保经过身份验证的请求获得读写访问权限,未经身份验证的请求将获得只读访问权限。
首先在视图模块中添加以下导入
from rest_framework import permissions
接着,下面的属性添加到SnippetList和SnippetDetail视图类。
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
06-在可浏览的API添加登录
如果您打开浏览器并浏览到可浏览的API,那么您将发现无法再创建新的代码段。为了做到这一点,我们需要能够以用户身份登录。
我们可以通过编辑项目级urls.py文件中的URLconf来添加的登录视图在可浏览API使用。
在文件顶部添加以下导入:
from django.conf.urls import include
而且,在文件末尾添加一个模式以包括登录和注销视图对于可浏览的API。
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
r’^api-auth/’模式的一部分实际上可以是您想要使用的任何URL。唯一的限制是包含的URL必须使用’rest_framework’命名空间。在Django 1.9+中,REST框架将设置命名空间,因此您可以将其删除。
现在,如果再次打开浏览器并刷新页面,您将在页面右上方看到一个“登录”链接。如果您以您之前创建的用户身份登录,则可以再次创建代码段。
创建了一些代码片段后,导航到“/ users /”端点,并注意到每个用户的代码字段中,该表示包含与每个用户相关联的代码段的列表。
07-对象级权限
好吧,我们希望所有的代码段都可以被任何人看到,但也要确保只有创建代码段的用户才能更新或删除它。
为此,我们将需要创建一个自定义权限。
在片段app中,创建一个新文件, permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
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
现在,我们可以通过编辑视图类中的permission_classes属性将该自定义权限添加到我们的代码段实例末端,在SnippetDetail中操作:
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)
确保导入IsOwnerOrReadOnly类。
from snippets.permissions import IsOwnerOrReadOnly
现在,如果再次打开浏览器,您会发现如果您以与创建代码段相同的用户身份登录,“DELETE”和“PUT”操作只会显示在代码段实例端点上。
08-使用API进行身份验证
因为我们现在有一组API的权限,如果我们要编辑任何代码片段,我们需要验证我们的请求。我们还没有设置任何身份验证类,所以默认值现在被应用,是SessionAuthentication和BasicAuthentication。
当我们通过Web浏览器与API进行交互时,我们可以登录,然后浏览器session将为请求提供所需的身份验证。
如果我们以编程方式与API交互,我们需要在每个请求上显式提供身份验证凭据。
如果我们尝试创建一个没有验证用户输入的代码段,我们会得到一个错误:
http POST http://127.0.0.1:8000/snippets/ code="print 123"
{
"detail": "Authentication credentials were not provided."
}
我们可以通过包括我们之前创建的一个用户的用户名和密码来成功完成之前的请求。
http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"
{
"id": 1,
"owner": "tom",
"title": "foo",
"code": "print 789",
"linenos": false,
"language": "python",
"style": "friendly"
}
09-概要总结
对于系统用户和他们创建的代码片段,我们现在已经在我们的Web API上获得了相当完善的权限设置。
在本教程的第5部分中,我们将介绍如何通过为突出显示的片段创建一个HTML节点来将所有内容结合在一起,并通过使用系统内部关系的超链接来提高API的聚合力。