zoukankan      html  css  js  c++  java
  • Django-Rest-Framework 教程: 4. 验证和权限

    到目前为止, 我们的API并未指明哪些人有权限编辑或删除snippet, 接下来我们要实现:

    • 为snippet增加创建者
    • 特定用户才能创建snippet
    • snippet创建者才能更新或删除该snippet
    • 未授权用户只能查看

    1. 为snippet model增加field

    我们现为snippet model增加两个field, 一个用于储存创建者信息, 另一个则用作储存高亮HTML信息:

        # snippets/models.py
        from django.db import models
        from pygments.lexers import get_all_lexers
        from pygments.styles import get_all_styles
    
        LEXERS = [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')
            highlighted = models.TextField()
    
            class Meta:
                ordering = ('created',)

    当执行save()时, 我们使用pygments生成高亮后的HTML:

        # snippets/models.py
        from pygments.lexers import get_lexer_by_name
        from pygments.formatters.html import HtmlFormatter
        from pygments import highlight
    
        class Snippet(models.Model):
    
            ...
    
            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 syncdb

    你可能需要再创建几个用户, 可以通过以下命令创建:

        python ./manage.py createsuperuser

    2. 为User model增加endpoints

    在serializer.py中增加UserSerializer:

        # snippets/serializers.py
        from django.contrib.auth.models import User
    
        class UserSerializer(serializers.ModelSerializer):
            snippets = serializers.PrimaryKeyRelatedField(many=True)
    
            class Meta:
                model = User
                fields = ('id', 'username', 'snippets')

    由于”snippets”是User的一个反向关系, 因此我们需要用field明确指明.

    我们只需要为user model添加只读的API, 因此使用ListAPIView和RetrieveAPIView即可:

        # snippets/views.py
        from django.contrib.auth.models import User
        from snippets.serializers import UserSerializer
    
    
        class UserList(generics.ListAPIView):
            queryset = User.objects.all()
            serializer_class = UserSerializer
    
    
        class UserDetail(generics.RetrieveAPIView):
            queryset = User.objects.all()
            serializer_class = UserSerializer

    最后修改urls.py, 添加users:

        url(r'^users/$', views.UserList.as_view()),
        url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),

    3. 关联user和snippet

    如果现在我们通过API创建snippet, 我们无法将创建者将其关联起来. 因为创建者信息并不是以serialized数据传进来的, 而是通过request获取的.

    我们的解决方法是重写SnippetList和SnippetDetail view的pre_save()方法. 该方法允许我们处理request或request URL中的任何信息.

        # snippets/views.py
        class SnippetList(APIView):
    
            ...
    
            def pre_save(self, obj):
                obj.owner = self.request.user
    
    
        class SnippetDetail(APIView):
    
            ...
    
            def pre_save(self, obj):
                obj.owner = self.request.user

    4. 更新 serializer

    现在snippet已经与创建者关联, 接下来我们修改serializer来反映该变化:

    # snippets/serializers.py
    class SnippetSerializer(serializers.ModelSerializer):
        owner = serializers.Field(source='owner.username')
    
        class Meta:
            model = Snippet
            fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')

    ower field十分有趣, source参数控制着使用snippet哪个attribute作为来源填充该field, 并且能使用”.”语法.

    Field类, 相对于其他field类(CharField, BooleanField等), 是只读field. 它能用作呈现序列化的数据, 但不会在凡序列化时被用做更新数据.

    5. 添加权限

    到此为止, snippet已经与user关联了. 接下来我们实现只有授权用户才能创建, 更新和删除snippet.

    Django REST Framework为我们提供了许多permission类. 在此, 我们使用IsAuthenticatedOrReadOnly, 它能保证只有授权用户才有读写权限, 而一般用户只有读得权限:

        # snippets/views.py
        from rest_framework import permissions
        class SnippetList(APIView):
    
            ...
    
            permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
    
    
        class SnippetDetail(APIView):
    
            ...
    
            permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    6. 增加可浏览的授权API

    在tutorial/urls.py中:

        # 在tutorial/urls.py
    
        urlpatterns = patterns('',
                           ...
        )
    
        urlpatterns += patterns('',
            url(r'^api-auth/', include('rest_framework.urls',
                                       namespace='rest_framework')),
        )

    r’^api-auth/’可以是你能想得到的所有pattern. 到此你可以使用/api-auth/进行登录了. 登录成功之后你才能创建snippet.

    添加好snippet之后, 在浏览/users/ endpoint, 你可以发现每个用户下都有对应的snippet的pk.

    7. 添加对象权限

    接下来, 我们实现只有snippet的创建者才能更新, 编辑或删除snippet, 创建snippets/permissions.py:

        # snippets/permissions.py
        from rest_framework import permissions
    
    
        class IsOwnerOrReadOnly(permissions.BasePermission):
            """
            允许创建者编辑的自定义权限
            """
    
            def has_object_permission(self, request, view, obj):
                # 任何request都有只读权限, 所以总是允许GET, HEAD 或 OPTIONS
                if request.method in permissions.SAFE_METHODS:
                    return True
    
                # 只有snippet的创建者有写的权限
                return obj.owner == request.user

    修改SnippetDetail view:

        # snippets/views.py
        from snippets.permissions import IsOwnerOrReadOnly
    
    
        class SnippetDetail(APIView):
    
            ...
    
            permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)

    8. 使用API授权

    目前为止, 我们没有设置 authentication classes, 因此 authentication classes 还是默认的SessionAuthentication和BasicAuthentication.

    当我们使用浏览器时, 我们可以通过浏览器登录并使用session授权接下来的request.

    但当我们使用程序调用API时, 我们必须为每次request提供授权信息:

        curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 789" -u tom:password
    
        {"id": 5, "owner": "tom", "title": "foo", "code": "print 789", "linenos": false, "language": "python", "style": "friendly"}

    原文链接: http://www.weiguda.com/blog/22/

  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/leo23/p/5051915.html
Copyright © 2011-2022 走看看