Django可以用LoginRequiredMixinPermissionRequiredMixin给类视图添加认证和权限,DRF做了高级封装,提供了更简洁的实现方式。我们通过继续学习官网教程来进行了解。

更新model

首先修改Snippet模型,添加2个字段:owner,存储snippet创建者,highlighted,存储高亮HTML。同时重写save方法,在同步数据库的时候,使用pygments包把code格式化后存到highlighted字段。修改后的snippets/models.py完整代码如下:

from django.db import modelsfrom pygments.lexers import get_all_lexersfrom pygments.styles import get_all_stylesfrom pygments.lexers import get_lexer_by_namefrom pygments.formatters.html import HtmlFormatterfrom pygments import highlightLEXERS = [item for item in get_all_lexers() if item[1]]LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])class Snippet(models.Model):    created = models.DateTimeField(auto_now_add=True)    title = models.CharField(max_length=100, blank=True, default='')    code = models.TextField()    linenos = models.BooleanField(default=False)    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)    owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)    highlighted = models.TextField()class Meta:        ordering = ['created']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 = 'table' if self.linenos else False        options = {'title': self.title} if self.title else {}        formatter = HtmlFormatter(style=self.style, linenos=linenos,                                  full=True, **options)        self.highlighted = highlight(self.code, lexer, formatter)super(Snippet, self).save(*args, **kwargs)

接着删除数据库和migrations,重新迁移数据库:

rm -f db.sqlite3rm -r snippets/migrationspython manage.py makemigrations snippetspython manage.py migrate

并创建超级管理员:

python manage.py createsuperuser

User添加Endpoint

Endpoint,表示API的具体网址。我们按照models.pyserializers.pyviews.pyurls.py的代码编写顺序,给User模型添加Endpoint。models.py直接使用Django默认User模型,不需要修改代码。serializers.py添加UserSerializer,由于User没有snippets字段,所以需要显式添加:

from django.contrib.auth.models import Userclass UserSerializer(serializers.ModelSerializer):    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())class Meta:        model = User        fields = ['id', 'username', 'snippets']

views.py添加只读的列表视图UserList和详情视图UserDetail,分别用到了ListAPIViewRetrieveAPIView

from django.contrib.auth.models import Userfrom snippets.serializers import UserSerializerclass UserList(generics.ListAPIView):    queryset = User.objects.all()    serializer_class = UserSerializerclass UserDetail(generics.RetrieveAPIView):    queryset = User.objects.all()    serializer_class = UserSerializer

urls.py添加访问路径:

path('users/', views.UserList.as_view()),path('users//', views.UserDetail.as_view()),

关联User和Snippet

如果使用POST方法请求http://127.0.0.1:8000/snippets/,尝试添加1条数据:会发现接口报错了:owner_id不能为空?因为前面只给Snippet添加了owner字段,还没有写反序列化更新模型的代码,所以通过请求访问视图,再尝试反序列化的时候,报错了。我们先修改视图SnippetList来修复这个问题:

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

SnippetList视图中重写perform_create()方法,意思是在保存时,把request.user值赋给owner字段。perform_create()方法的源码是:

class CreateModelMixin:"""    Create a model instance.    """def create(self, request, *args, **kwargs):        serializer = self.get_serializer(data=request.data)        serializer.is_valid(raise_exception=True)        self.perform_create(serializer)        headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):        serializer.save()

再修改snippets/serializers.py,添加owner字段,支持序列化:

class SnippetSerializer(serializers.ModelSerializer):# ReadOnlyField表示只能序列化为JSON,不能反序列化更新模型# 也可以改成CharField(read_only=True)    owner = serializers.ReadOnlyField(source='owner.username')class Meta:        model = Snippet        fields = ['id', 'title', 'code', 'linenos', 'language', 'style', 'owner']

注意Meta.fields也要加上owner哦。

再请求一次:刚才的错误没有了,但是报了个新的错误:Snippet.owner必须是User实例,给它赋值的是AnonymousUser(匿名用户),导致ValueError了。这个报错是发生这条代码:

serializer.save(owner=self.request.user)

也就是说请求访问视图后,进行反序列化了,但是反序列化失败了。非常奇怪!我们的请求中并没有用户信息,正常来说在访问视图的时候就该被拦截了。

给视图添加认证

我们需要让API更符合常规,让未认证的用户不能执行视图中的代码。DRF提供了rest_framework .permissions来给视图添加认证:其中IsAuthenticatedOrReadOnly表示只有认证了才能读写,否则只能读。把它添加到SnippetListSnippetDetail视图中:

from rest_framework import permissionspermission_classes = [permissions.IsAuthenticatedOrReadOnly]

再请求试试,刚才的错误没有了,API返回的是需要提供用户凭证:

登录视图

如果用浏览器打开http://127.0.0.1:8000/snippets/,会发现只有GET方法没有POST,这是因为需要添加DRF登录视图,在tutorial/urls.py中添加rest_framework.urls

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

api-auth/可以自定义。

刷新页面右上角就会出现Log in按钮,登录后就能POST了。

对象级权限

为了更细粒度的控制权限,让用户只能编辑自己创建的snippet,新建snippets/permissions.py

from rest_framework import permissionsclass 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

新增IsOwnerOrReadOnly权限,继承了permissions.BasePermission,重写了has_object_permission()方法。接着在snippets/views.py中给SnippetDetail加上:

from snippets.permissions import IsOwnerOrReadOnlypermission_classes = [permissions.IsAuthenticatedOrReadOnly,                      IsOwnerOrReadOnly]

试下访问其他用户创建的snippet,发现只能查看:访问自己创建的snippet,可以修改和删除:

自定义权限

以上是官网的示例,我在Postman测试了下,发现超管dongfanger可以创建snippet普通用户player也可以创建snippet我想让普通用户不能创建,只能超管创建。仿照官网示例,在snippets/permissions.py中添加IsAdminOrReadOnly

class IsAdminOrReadOnly(permissions.BasePermission):def has_permission(self, request, view):return request.user.is_superuser

接着给SnippetList加上:

permission_classes = [permissions.IsAuthenticatedOrReadOnly,                      IsAdminOrReadOnly]

用普通用户尝试创建,提示没有权限:用超级管理员尝试创建,成功:

其他认证方式

本文使用的认证方式是默认的SessionAuthenticationBasicAuthentication,只要数据库的用户名、密码和请求中的用户凭证(用户名、密码)匹配上了,就认为认证成功。如果要实现token或jwt认证,需要使用到rest_framework.authenticationrest_framework_jwt.authentication

pip install djangorestframework-jwt

这一部分内容官网教程中并没有提及,等我们把教程学完了,以后再找时间来介绍。

东方说

DRF实现认证和权限的关键在于新增permissions.py模块,编写class,继承permissions.BasePermission,重写has_permission()has_object_permission()方法,再添加class到类视图的permission_classes中。这块的内容比Django的认证系统那套简洁,但是有点混淆,另外我之前参照网上实现了一版JWT,也有点不一样。看来还得写篇对比的文章才行。

参考资料:https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/

django 不包括字段 序列化器_DRF比Django的认证和权限高在哪里相关推荐

  1. django 不包括字段 序列化器_手写一个Django序列化功能

    本文章的代码已上传至github上(github包含了更多功能,相关文章后续更新) AGL1994/django-building​github.com 前言 目前Django比较知名的序列化框架有D ...

  2. django序列化器嵌套_Django Rest Framework中用于OneToOne字段的序列化程序中的嵌套关​​系

    django序列化器嵌套 The Django Rest Framework (DRF) is one of the effectively written frameworks around Dja ...

  3. 谈谈Django REST Framework(DRF)中的序列化器

    摘要 Django REST Framework(DRF)是一个强大的工具,可以帮助我们构建和处理RESTful API.其中的序列化器(Serializers)是其核心组件之一,它允许我们快速有效地 ...

  4. 关于Django中,实现序列化的几种不同方法

    前言 关于序列化操作,就是将一个可迭代的数据结构,通过便利的方式进行我们所需要的操作. 今天历来归纳一下,Django中的几种不同得分方法,已经Django-restframework提供的方法 创建 ...

  5. 客户端序列码生成_Django REST Framework教程(2): 序列化器介绍及开发基于函数视图的API...

    在上篇文章中,我们已经介绍了为什么要学习DRF,什么是序列化以及什么是符合RESTful规范的Web API.在本篇文章中我们将以博客为例,使用DRF提供的序列化器(Serializers类)开发两个 ...

  6. django中序列化器字段参数、关联字段

    一.PrimaryKeyRelatedField 1.可以定义PrimaryKeyRelatedField来获取关联表的外键值 2.如果通过父表获取从表数据,默认需要使用从表模型类名小写_set作为序 ...

  7. Django REST Framework教程(4): 玩转序列化器(Serializer)

    在前面的文章中我们以博客为例,自定义了一个简单的 ArticleSerializer 类, 并分别以函数视图(FBV)和基于类的视图(CBV)编写了博客文章列表资源和单篇文章资源的API,支持客户端以 ...

  8. 快速上手Django(六) -Django之Django drf 序列化器Serializer类

    文章目录 快速上手Django(六) -Django之Django drf 序列化器Serializer类 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSeria ...

  9. Django 基础(13)-Django drf 序列化器类to_representation和to_internal_value(处理返回的日期格式)、序列化类 ModelSerializer

    文章目录 一.Django drf 序列化 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSerializer 5. DRF序列化器to_representatio ...

最新文章

  1. Java打包问题之一:打包出现java.io.IOException: invalid header field
  2. 反射机制2,Class类的使用
  3. rxjs angular_Angular RxJS深度
  4. react如何遍历并比较_[前端进阶] 这可能是最通俗易懂的React 渲染原理及性能优化...
  5. 国际贸易术语解释通则(DDP 完税后交货(……指定目的港))
  6. ATM(异步传输模式)是什么?
  7. 先马后看!详解线性回归、朴素贝叶斯、随机森林在R和Python中的实现应用!(附代码)...
  8. 实现ISA2004的WPAD(自动发现功能)
  9. 661. Image Smoother
  10. 计算机的未来展望英语作文,展望未来英语作文5篇
  11. pdf签名无效解决办法_强大的PDF编辑工具Wondershare PDFelement
  12. R:CSV读取问题Error in read.table(file = file, header = header, sep = sep, quote = quote, : 列的数目比列的名字要多
  13. Redis教程(一) Redis入门教程
  14. keras+learning
  15. 专注力的重要性和提高的方法
  16. redis php 书,predis VS phpRedis
  17. msf之ms17-010永恒之蓝漏洞
  18. Whale帷幄 - 车企数字化营销转型
  19. 23考研 长安大学846计算机考研复试《数据库》
  20. Tracker--追踪者

热门文章

  1. WPF内嵌WCF服务对外提供接口
  2. 18.7 修改IP地址
  3. [Leetcode] Path Sum II路径和
  4. 再看2015 --北漂程序员的成长史
  5. 小苏的Shell编程笔记之六--Shell中的函数
  6. [转载] python中list的方法有哪些_Python 列表(list)中的方法
  7. [转载] python学习-基础教程、深度学习
  8. [转载] 这100道练习,带你玩转Numpy
  9. 开启和关闭oracle数据库中的审计功能
  10. 最长不下降子序列的长度