django 不包括字段 序列化器_DRF比Django的认证和权限高在哪里
LoginRequiredMixin
和PermissionRequiredMixin
给类视图添加认证和权限,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.py
→serializers.py
→views.py
→urls.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
,分别用到了ListAPIView
和RetrieveAPIView
:
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
表示只有认证了才能读写,否则只能读。把它添加到SnippetList
和SnippetDetail
视图中:
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]
用普通用户尝试创建,提示没有权限:用超级管理员尝试创建,成功:
其他认证方式
本文使用的认证方式是默认的SessionAuthentication
和BasicAuthentication
,只要数据库的用户名、密码和请求中的用户凭证(用户名、密码)匹配上了,就认为认证成功。如果要实现token或jwt认证,需要使用到rest_framework.authentication
:或rest_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的认证和权限高在哪里相关推荐
- django 不包括字段 序列化器_手写一个Django序列化功能
本文章的代码已上传至github上(github包含了更多功能,相关文章后续更新) AGL1994/django-buildinggithub.com 前言 目前Django比较知名的序列化框架有D ...
- django序列化器嵌套_Django Rest Framework中用于OneToOne字段的序列化程序中的嵌套关系
django序列化器嵌套 The Django Rest Framework (DRF) is one of the effectively written frameworks around Dja ...
- 谈谈Django REST Framework(DRF)中的序列化器
摘要 Django REST Framework(DRF)是一个强大的工具,可以帮助我们构建和处理RESTful API.其中的序列化器(Serializers)是其核心组件之一,它允许我们快速有效地 ...
- 关于Django中,实现序列化的几种不同方法
前言 关于序列化操作,就是将一个可迭代的数据结构,通过便利的方式进行我们所需要的操作. 今天历来归纳一下,Django中的几种不同得分方法,已经Django-restframework提供的方法 创建 ...
- 客户端序列码生成_Django REST Framework教程(2): 序列化器介绍及开发基于函数视图的API...
在上篇文章中,我们已经介绍了为什么要学习DRF,什么是序列化以及什么是符合RESTful规范的Web API.在本篇文章中我们将以博客为例,使用DRF提供的序列化器(Serializers类)开发两个 ...
- django中序列化器字段参数、关联字段
一.PrimaryKeyRelatedField 1.可以定义PrimaryKeyRelatedField来获取关联表的外键值 2.如果通过父表获取从表数据,默认需要使用从表模型类名小写_set作为序 ...
- Django REST Framework教程(4): 玩转序列化器(Serializer)
在前面的文章中我们以博客为例,自定义了一个简单的 ArticleSerializer 类, 并分别以函数视图(FBV)和基于类的视图(CBV)编写了博客文章列表资源和单篇文章资源的API,支持客户端以 ...
- 快速上手Django(六) -Django之Django drf 序列化器Serializer类
文章目录 快速上手Django(六) -Django之Django drf 序列化器Serializer类 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSeria ...
- Django 基础(13)-Django drf 序列化器类to_representation和to_internal_value(处理返回的日期格式)、序列化类 ModelSerializer
文章目录 一.Django drf 序列化 1. 背景 2. 使用思路 3. 代码demo 4. [重要]序列化类 ModelSerializer 5. DRF序列化器to_representatio ...
最新文章
- Java打包问题之一:打包出现java.io.IOException: invalid header field
- 反射机制2,Class类的使用
- rxjs angular_Angular RxJS深度
- react如何遍历并比较_[前端进阶] 这可能是最通俗易懂的React 渲染原理及性能优化...
- 国际贸易术语解释通则(DDP 完税后交货(……指定目的港))
- ATM(异步传输模式)是什么?
- 先马后看!详解线性回归、朴素贝叶斯、随机森林在R和Python中的实现应用!(附代码)...
- 实现ISA2004的WPAD(自动发现功能)
- 661. Image Smoother
- 计算机的未来展望英语作文,展望未来英语作文5篇
- pdf签名无效解决办法_强大的PDF编辑工具Wondershare PDFelement
- R:CSV读取问题Error in read.table(file = file, header = header, sep = sep, quote = quote, : 列的数目比列的名字要多
- Redis教程(一) Redis入门教程
- keras+learning
- 专注力的重要性和提高的方法
- redis php 书,predis VS phpRedis
- msf之ms17-010永恒之蓝漏洞
- Whale帷幄 - 车企数字化营销转型
- 23考研 长安大学846计算机考研复试《数据库》
- Tracker--追踪者