[oldboy-django][2深刻django]rest-framework教程

# rest-framework教程
    - settings.py
        INSTALL-APPS = [
            'snippets',  # app
            'rest-framework',
        ]
    
    - 建立model
        # -*- coding: utf-8 -*-
        from __future__ import unicode_literals

        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)

            class Meta:
                ordering = ('created',)
    
    - 建立serializer 麻煩

        # -*- coding: utf-8 -*-
        from rest_framework import serializers
        from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


        # 不繼承ModelSerializer, 本身定義create, update,這兩個函數在SnippetSerializer對象.save()執行事被調用
        class SnippetSerializer(serializers.Serializer):
            id = serializers.IntegerField(read_only=True)
            title = serializers.CharField(required=False, allow_blank=True, max_length=100)
            code = serializers.CharField(style={'base_template': 'textarea.html'})
            linenos = serializers.BooleanField(required=False)
            language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
            style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

            def create(self, validated_data):
                """
                Create and return a new `Snippet` instance, given the validated data.
                """
                return Snippet.objects.create(**validated_data)

            def update(self, instance, validated_data):
                """
                Update and return an existing `Snippet` instance, given the validated data.
                """
                instance.title = validated_data.get('title', instance.title)
                instance.code = validated_data.get('code', instance.code)
                instance.linenos = validated_data.get('linenos', instance.linenos)
                instance.language = validated_data.get('language', instance.language)
                instance.style = validated_data.get('style', instance.style)
                instance.save()
                return instance

    - 建立Serializer,簡便
        class SnippetSerializer(serializers.ModelSerializer):
            class Meta:
                model = Snippet
                fields = ('id', 'title', 'code', 'linenos', 'language', 'style') 
        
        # 和上面是同樣的,ModelSerializer裏面定義了create,update方法
        # 不信你執行下面語句
            serializer = SnippetSerializer()
            print(repr(serializer))
        
        
    - 添加數據(添加兩條數據)
        python manage.py shell
        >>>from snippets.models import Snippet
        >>> snippet = Snippet(code='foo = "bar"\n')
        >>> snippet.save()
        >>>
        >>>
        >>> snippet = Snippet(code='print "hello, world"\n')
        >>> snippet.save()

    - 使用serializer 獲得dict數據 : serializer對象.data
        >>> snippet = Snippet.objects.all()[1]
        >>> serializer = SnippetSerializer(snippet)
        >>> serializer.data
        {'style': 'friendly', 'code': u'print "hello, world"\n', 'language': 'python', 'title': u'', 'linenos': False, 'id': 2}
    
    - 使用serializer獲得Json數據  --序列化
        >>> from rest_framework.renderers import JSONRenderer
        >>> snippet = Snippet.objects.all()[1]
        >>> serializer = SnippetSerializer(snippet)
        >>> content= JSONRenderer().render(serializer.data)
        >>> content
        '{"id":2,"title":"","code":"print \\"hello, world\\"\\n","linenos":false,"language":"python","style":"friendly"}'
        >>>

    - 使用serializer反序列化獲得字典數據

        >>> from rest_framework.renderers import JSONRenderer
        >>> content= JSONRenderer().render(serializer.data)
        >>> content
        '{"id":2,"title":"","code":"print \\"hello, world\\"\\n","linenos":false,"language":"python","style":"friendly"}'
        >>> from rest_framework.parsers import JSONParser
        >>> data = JSONParser().parse(content)
            # 會報錯,由於content不是句柄(可讀)
            AttributeError: 'str' object has no attribute 'read'
        >>> f = open('a.data','wb')
        >>> f.write(content)
        >>> f.close()
        >>> f = open('a.data','rb')
        >>> data = JSONParser().parse(f)
        >>> data
            {u'style': u'friendly', u'code': u'print "hello, world"\n', u'language': u'python', u'title': u'', u'linenos': False, u'id': 2}

    - 使用serializer插入數據  -- data爲上面的data
        >>> serializer = SnippetSerializer(data=data)  # 至關於插入數據
        >>> serializer.is_valid()
        True
        >>> serializer.validated_data
        OrderedDict([(u'title', u''), (u'code', u'print "hello, world"'), (u'linenos', False), (u'language', 'python'), (u'style', 'friendly')])
        >>> serializer.save()
        <Snippet: Snippet object>
        
        # 數據庫保存, 查看數據庫會發現已經多了一條數據
    
    - 將多個對象序列化many=True
        >>> serializer = SnippetSerializer(Snippet.objects.all(), many=True)
        >>> serializer.data
        [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), Orde
        redDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]),
        OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
        ]

    
    - 建立views
        -- 工程.url
            urlpatterns = [
                url(r'^admin/', admin.site.urls),
                url(r'^', include('snippets.urls')),
            ]
        -- snippets.url
        urlpatterns = [
            url(r'^snippets/$', views.snippet_list),
            url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
        ]
        -- 視圖函數
            # -*- coding: utf-8 -*-
            from __future__ import unicode_literals

            from django.shortcuts import render, HttpResponse
            from django.http import JsonResponse
            from snippets.models import Snippet
            from snippets.serializer import SnippetSerializer


            # Create your views here.
            def snippet_list(request):
                if request.method == 'GET':
                    snippets = Snippet.objects.all()
                    serializer = SnippetSerializer(snippets, many=True)
                    return JsonResponse(serializer.data, safe=False)


            def snippet_detail(request, pk):
                try:
                    snippet = Snippet.objects.get(pk=pk)
                except Snippet.DoesNotExist:
                    return HttpResponse(status=404)

                if request.method == 'GET':
                    serializer = SnippetSerializer(snippet)
                    return JsonResponse(serializer.data)

    
View Code

 官網:http://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/html

 中文翻譯比較好:http://www.cnblogs.com/zivwong/p/7461764.htmlpython

-- serializer序列化和反序列化shell

-# rest-framework教程
    - settings.py
        INSTALL-APPS = [
            'snippets',  # app
            'rest-framework',
        ]
    
    - 建立model
        # -*- coding: utf-8 -*-
        from __future__ import unicode_literals

        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)

            class Meta:
                ordering = ('created',)
    
    - 建立serializer 麻煩

        # -*- coding: utf-8 -*-
        from rest_framework import serializers
        from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


        # 不繼承ModelSerializer, 本身定義create, update,這兩個函數在SnippetSerializer對象.save()執行事被調用
        class SnippetSerializer(serializers.Serializer):
            id = serializers.IntegerField(read_only=True)
            title = serializers.CharField(required=False, allow_blank=True, max_length=100)
            code = serializers.CharField(style={'base_template': 'textarea.html'})
            linenos = serializers.BooleanField(required=False)
            language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
            style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

            def create(self, validated_data):
                """
                Create and return a new `Snippet` instance, given the validated data.
                """
                return Snippet.objects.create(**validated_data)

            def update(self, instance, validated_data):
                """
                Update and return an existing `Snippet` instance, given the validated data.
                """
                instance.title = validated_data.get('title', instance.title)
                instance.code = validated_data.get('code', instance.code)
                instance.linenos = validated_data.get('linenos', instance.linenos)
                instance.language = validated_data.get('language', instance.language)
                instance.style = validated_data.get('style', instance.style)
                instance.save()
                return instance

    - 建立Serializer,簡便
        class SnippetSerializer(serializers.ModelSerializer):
            class Meta:
                model = Snippet
                fields = ('id', 'title', 'code', 'linenos', 'language', 'style') 
        
        # 和上面是同樣的,ModelSerializer裏面定義了create,update方法
        # 不信你執行下面語句
            serializer = SnippetSerializer()
            print(repr(serializer))
        
        
    - 添加數據(添加兩條數據)
        python manage.py shell
        >>>from snippets.models import Snippet
        >>> snippet = Snippet(code='foo = "bar"\n')
        >>> snippet.save()
        >>>
        >>>
        >>> snippet = Snippet(code='print "hello, world"\n')
        >>> snippet.save()

    - 使用serializer 獲得dict數據 : serializer對象.data
        >>> snippet = Snippet.objects.all()[1]
        >>> serializer = SnippetSerializer(snippet)
        >>> serializer.data
        {'style': 'friendly', 'code': u'print "hello, world"\n', 'language': 'python', 'title': u'', 'linenos': False, 'id': 2}
    
    - 使用serializer獲得Json數據  --序列化
        >>> from rest_framework.renderers import JSONRenderer
        >>> snippet = Snippet.objects.all()[1]
        >>> serializer = SnippetSerializer(snippet)
        >>> content= JSONRenderer().render(serializer.data)
        >>> content
        '{"id":2,"title":"","code":"print \\"hello, world\\"\\n","linenos":false,"language":"python","style":"friendly"}'
        >>>

    - 使用serializer反序列化獲得字典數據

        >>> from rest_framework.renderers import JSONRenderer
        >>> content= JSONRenderer().render(serializer.data)
        >>> content
        '{"id":2,"title":"","code":"print \\"hello, world\\"\\n","linenos":false,"language":"python","style":"friendly"}'
        >>> from rest_framework.parsers import JSONParser
        >>> data = JSONParser().parse(content)
            # 會報錯,由於content不是句柄(可讀)
            AttributeError: 'str' object has no attribute 'read'
        >>> f = open('a.data','wb')
        >>> f.write(content)
        >>> f.close()
        >>> f = open('a.data','rb')
        >>> data = JSONParser().parse(f)
        >>> data
            {u'style': u'friendly', u'code': u'print "hello, world"\n', u'language': u'python', u'title': u'', u'linenos': False, u'id': 2}

    - 使用serializer插入數據  -- data爲上面的data
        >>> serializer = SnippetSerializer(data=data)  # 至關於插入數據
        >>> serializer.is_valid()
        True
        >>> serializer.validated_data
        OrderedDict([(u'title', u''), (u'code', u'print "hello, world"'), (u'linenos', False), (u'language', 'python'), (u'style', 'friendly')])
        >>> serializer.save()
        <Snippet: Snippet object>
        
        # 數據庫保存, 查看數據庫會發現已經多了一條數據
    
    - 將多個對象序列化many=True
        >>> serializer = SnippetSerializer(Snippet.objects.all(), many=True)
        >>> serializer.data
        [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), Orde
        redDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]),
        OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
        ]

    
    - 建立views
        -- 工程.url
            urlpatterns = [
                url(r'^admin/', admin.site.urls),
                url(r'^', include('snippets.urls')),
            ]
        -- snippets.url
        urlpatterns = [
            url(r'^snippets/$', views.snippet_list),
            url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
        ]
        -- 視圖函數
            # -*- coding: utf-8 -*-
            from __future__ import unicode_literals

            from django.shortcuts import render, HttpResponse
            from django.http import JsonResponse
            from snippets.models import Snippet
            from snippets.serializer import SnippetSerializer


            # Create your views here.
            def snippet_list(request):
                if request.method == 'GET':
                    snippets = Snippet.objects.all()
                    serializer = SnippetSerializer(snippets, many=True)
                    return JsonResponse(serializer.data, safe=False)


            def snippet_detail(request, pk):
                try:
                    snippet = Snippet.objects.get(pk=pk)
                except Snippet.DoesNotExist:
                    return HttpResponse(status=404)

                if request.method == 'GET':
                    serializer = SnippetSerializer(snippet)
                    return JsonResponse(serializer.data)
View Code

-- request,response,fbv數據庫

-# rest-framework核心教程(request, response, api_view, APIVIEW)
    -- request
        # 繼承HttpRequest
        # request.data屬性相比HttpRequest.POST更靈活:處理更復雜數據且對POST,PUT,PATCH請求都有效
            request.POST  # Only handles form data.  Only works for 'POST' method.
            request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.
    -- response
        # 根據客戶端請求不一樣的數據而渲染相應數據
        return Response(data)  # Renders to content type as requested by the client.
    -- status code
        # 可讀性更好,並且包含錯誤信息
    -- 裝飾器
        -- fbv裝飾器
            @api_view是 工做fbv, 對cbv沒有效果的
        -- cbv裝飾器
            APIView是對FBV有效果
        -- 好處:
            a.保證了view接收到的request實例
            b.會將context添加到response中
            c.還會返回正確的狀態碼
            
    -- 使用上面四個核心東西(再也不用JSONResponse)
    
        # -*- coding: utf-8 -*-
        from __future__ import unicode_literals

        from django.shortcuts import render, HttpResponse
        # from django.http import JsonResponse
        from rest_framework.response import Response
        from snippets.models import Snippet
        from snippets.serializer import SnippetSerializer

        from rest_framework.decorators import api_view
        from rest_framework import status


        @api_view(['GET','POST'])
        def snippet_list(request):
            if request.method == 'GET':
                snippets = Snippet.objects.all()
                serializer = SnippetSerializer(snippets, many=True)
                return Response(serializer.data)
            elif request.method == 'POST':
                # add snippet obj
                serializer = SnippetSerializer(data=request.data) # 注意這裏版本不一樣可能不同python3應該是data=request.DATA
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data, status=status.HTTP_201_CREATED)
                else:
                    return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
    
    
    -- 控制渲染給客戶端數據的格式
        -- 要修改一些東西
            -- 首先是要先設置url
                from django.conf.urls import patterns, url
                from rest_framework.urlpatterns import format_suffix_patterns

                urlpatterns = [
                    url(r'^snippets/$', 'snippet_list'),
                    url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'),
                ]

                urlpatterns = format_suffix_patterns(urlpatterns)
            
            -- 其次,要修改view,每一個視圖函數添加format=None參數
            
            
        -- 使用
            -- 默認是api (瀏覽器看到)
                http://127.0.0.1:8000/snippets/
            
            -- 使用Accept頭部信息控制response返回格式:
                curl http://127.0.0.1:8000/snippets/ -H 'Accept: application/json'  # JSON
            
            -- 經過url的後綴來控制response返回格式
                curl http://127.0.0.1:8000/snippets/.json
                curl http://127.0.0.1:8000/snippets/.api
    
    -- 控制提交數據的格式 提示request.DATA的靈活性
        之前提交數據都是經過表單提交, -d  後面接的字符串格式 "key=value"
            curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
        
        使用Json提交 注意多了-H , -d的數據是Json
            curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
        
    
    -- 測試
        - windows使用curl
            -- 下載curl
                https://curl.haxx.se/download.html
            -- 解壓將curl.exe拷貝到工程目錄
            
            -- 執行curl http://127.0.0.1:8000/snippets/
        
        - get 
            --  curl http://127.0.0.1:8000/snippets/
        
        - post
            -- curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
View Code

-- CBVdjango

-# 使用CBV縮減代碼和解耦
    - 使用CBV, url注意 as_view()
        urlpatterns = [
            url(r'^snippets/$', views.SnippetList.as_view()),
            url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
        ]
            
    - 視圖類的編寫繼承APIVIEW, 
        from snippets.models import Snippet
        from snippets.serializer import SnippetSerializer
        from django.http import Http404
        from rest_framework.views import APIView
        from rest_framework.response import Response
        from rest_framework import status


        class SnippetList(APIView):
            """
            List all snippets, or create a new snippet.
            """

            def get(self, request, format=None):
                snippets = Snippet.objects.all()
                serializer = SnippetSerializer(snippets, many=True)
                return Response(serializer.data)

            def post(self, request, format=None):
                serializer = SnippetSerializer(data=request.data)
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data, status=status.HTTP_201_CREATED)
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


        class SnippetDetail(APIView):
            """
            Retrieve, update or delete a snippet instance.
            """

            def get_object(self, pk):
                try:
                    return Snippet.objects.get(pk=pk)
                except Snippet.DoesNotExist:
                    raise Http404

            def get(self, request, pk, format=None):
                snippet = self.get_object(pk)
                serializer = SnippetSerializer(snippet)
                return Response(serializer.data)

            def put(self, request, pk, format=None):
                snippet = self.get_object(pk)
                serializer = SnippetSerializer(snippet, data=request.data)
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data)
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

            def delete(self, request, pk, format=None):
                snippet = self.get_object(pk)
                snippet.delete()
                return Response(status=status.HTTP_204_NO_CONTENT)
View Code

-- GCBVjson

-# 使用GCBV縮減代碼, 代碼超簡單
    from snippets.models import Snippet
    from snippets.serializer import SnippetSerializer
    from rest_framework import generics


    class SnippetList(generics.ListCreateAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer


    class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
View Code

-- 驗證和權限windows

-# 驗證和權限
# 驗證(登陸)和權限

    - 只有通過登陸後的用戶才能具有某些權限
    
    - 自定義一些權限,來設置某些視圖函數的權限
    

# 需求
    - 增長權限: 只有登陸後才能建立snippet, 不然只能查看, 對應的視圖函數爲Snippet_list
     
    - 增長權限: 只有代碼的建立者,才能修改, 不然只能查看, 對應的視圖函數爲Snippet_detail

# 設計
    - 登陸驗證
        建立者owner關聯到User, 利用django rest framework 的permissions中的IsAuthoridOrReady
    
    - 建立者才能修改
        - 建立者字段owner,
        - 建立權限類,自定義只有建立者才能修改
    
    - 核心
        - 關聯           -- models.py
        - serializer    -- serialziers.py    
        - 自定義權限    -- permission.py    
        - 登陸權限        -- rest_framework.permisson.IsAuthenticatedOrReadOnly
        
    - 補充
        - 頁面出現登陸button -- project level urls.py
            urlpatterns += [
                url(r'^api-auth/', include('rest_framework.urls',
                                           namespace='rest_framework')),
            ]
            
        - 關聯
                def perform_create(self, serializer):
                    serializer.save(owner=self.request.user)
        
-# 實現
    -- models.py
        # -*- coding: utf-8 -*-
        from __future__ import unicode_literals

        from django.db import models
        from django.contrib.auth.models import User
        from pygments.lexers import get_all_lexers
        from pygments.styles import get_all_styles
        from pygments.lexers import get_lexer_by_name
        from pygments.formatters.html import HtmlFormatter
        from pygments import highlight

        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)

            # add two fields, one is owner field, which is used to represent the user who create the snippet
            # other one is highlighted field, will be used to store the highlighted HTML
            owner = models.ForeignKey(User, related_name="snippets", on_delete=models.CASCADE)
            highlighted = models.TextField()

            class Meta:
                ordering = ('created',)

            # overwrite save(self,)
            # 當save()時,須要將高亮HTML寫到highligthed裏面


            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)

    -- serializers.py
        # -*- coding: utf-8 -*-
        from django.contrib.auth.models import User
        from newsnippets.models import Snippet
        from rest_framework import serializers


        class SnippetSerializer(serializers.ModelSerializer):
            owner = serializers.CharField(source="owner.username", read_only=True)

            class Meta:
                model = Snippet
                fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')

        # 由於已經關聯User, 因此必定要序列化
        class UserSerializer(serializers.ModelSerializer):
            snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

            class Meta:
                model = User
                fields = ('id', 'username', 'snippets')

    -- views.py
        # -*- coding: utf-8 -*-
        from __future__ import unicode_literals

        from newsnippets.models import Snippet
        from newsnippets.serializers import SnippetSerializer
        from rest_framework import generics
        from rest_framework import permissions
        from newsnippets.permissions import IsOwnerOrReadOnly


        class SnippetList(generics.ListCreateAPIView):
            queryset = Snippet.objects.all()
            serializer_class = SnippetSerializer
            # 只有通過驗證的request才能修改
            # 沒有通過驗證的request只能查看
            permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                                  IsOwnerOrReadOnly)

            # 將snippet和user關聯起來,由於user是經過request傳進來的
            # 解決辦法是重寫perform_create
            def perform_create(self, serializer):
                serializer.save(owner=self.request.user)


        class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
            queryset = Snippet.objects.all()
            serializer_class = SnippetSerializer

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

            permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                                  IsOwnerOrReadOnly)


        from django.contrib.auth.models import User
        from newsnippets.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

    -- 登陸權限
        from rest_framework import permissions.IsAuthenticatedOrReadOnly
    
    -- 自定義權限
    
        # -*- coding: utf-8 -*-
        from rest_framework import permissions


        # 須要添加一個權限:只有建立者才能修改,或者只能查看
        # 以後見權限添加到views裏面的permission_classes
        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    
    -- 將權限添加到views
         permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly)
    
    -
View Code

-- 超連接實現不一樣model之間跳轉,分頁api

- #超連接提供模型之間的關聯
    存在問題:
        - 訪問http://127.0.0.1:8000/users/時看到的用戶列表,
          沒有提供連接,指點點擊連接能夠查看某個用戶的詳情,好比不能跳轉到http://127.0.0.1:8000/users/2
         
        - 訪問http://127.0.0.1:8000/snippets/一樣存在問題
        
        - 並且users 和snippets沒有跳轉
        
    解決問題:
        - 設計根url(首頁/),該頁面能夠訪問全部模型(snippet和user)
           # views.py增長一個view , 這裏採用fbv
           
            from rest_framework.decorators import api_view
            from rest_framework.response import Response
            from rest_framework.reverse import reverse


            @api_view(['GET'])
            def api_root(request, format=None):
                return Response({
                    'users': reverse('user-list', request=request, format=format),
                    'snippets': reverse('snippet-list', request=request, format=format)
                })
    
            # 注意還須要設置    /  ---> api_root的映射關係
            
            # 模板也已經設置了
            
            # reverse,因此user-list是某個url的name, 以後必定要設置
        
            # 目前訪問首頁的結果, 能夠提供了超連接跳轉到users, 和snippets
                Api Root
                GET /
                HTTP 200 OK
                Allow: OPTIONS, GET
                Content-Type: application/json
                Vary: Accept

                {
                    "users": "http://127.0.0.1:8000/new/users/",
                    "snippets": "http://127.0.0.1:8000/new/snippets/"
                }
         
        - 添加超連接,當點擊超連接時能夠看到高亮代碼--返回html,若是返回json,那可視化就不行了;
            # 返回html
                REST framework爲咱們提供了兩種方式來呈現HTML,一種是使用已有的模板(咱們平時開發Django更經常使用的那種方式),另外一種就是使用已經構建好的HTML代碼。在這裏咱們會使用第二種方法
                剛纔已經說了每次保存數據時都會自動更新生成新的HTML代碼,而這個由pygments生成的代碼就保存在Snippet下的highlighted,因此有瀏覽器渲染並呈現highlighted下的HTML代碼就好了。
                
                renderer_classes = (renderers.StaticHTMLRenderer,)
        
            # 編寫GCBV
                from rest_framework import renderers
                from rest_framework.response import Response

                class SnippetHighlight(generics.GenericAPIView):
                    queryset = Snippet.objects.all()
                    renderer_classes = (renderers.StaticHTMLRenderer,)

                    def get(self, request, *args, **kwargs):
                        snippet = self.get_object()
                        return Response(snippet.highlighted)
            
            # 編寫url
                url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
                
            
            # 測試
                瀏覽器輸入:
                http://127.0.0.1:8000/new/snippets/1/highlight/
        
        
        - 將高亮代碼超連接添加到new/snippet/1/頁面
            # 修改SnippetSerailizer添加一個highlight字段,而且設置值爲超連接,
                highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
                注意view_name參數,命名空間, format="html", html顯示高亮代碼
            # fields
                fields = ('url', 'id', 'highlight', 'owner',
                  'title', 'code', 'linenos', 'language', 'style')
                
                注意多了個url, highlight
                
            # 測試
                http://127.0.0.1:8000/new/snippets/1/
                能夠看到
                {
                    "url": "http://127.0.0.1:8000/new/snippets/1/",
                    "id": 1,
                    "title": "test 1",
                    "highlight": "http://127.0.0.1:8000/new/snippets/1/highlight/",
                    "code": "a = 2",
                    "linenos": true,
                    "language": "python3",
                    "style": "friendly",
                    "owner": "lzp"
                }
                
        - 將snippet超連接添加到user頁面, 便可以看到
                snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)

            # 測試
                http://127.0.0.1:8000/new/users/
                
                HTTP 200 OK
                Allow: GET, HEAD, OPTIONS
                Content-Type: application/json
                Vary: Accept

                [
                    {
                        "url": "http://127.0.0.1:8000/new/users/1/",
                        "id": 1,
                        "username": "lzp",
                        "snippets": [
                            "http://127.0.0.1:8000/new/snippets/1/"  # 能夠看到全部snippets的超連接
                        ]
                    }
                ]
            
        - 分頁
            REST_FRAMEWORK = {
                'PAGE_SIZE': 10
            }
View Code
相關文章
相關標籤/搜索