2018-12-10 rest_framework總結

django-rest-framework,是一套基于Django 的 REST 框架,是一個強大靈活的構建 Web API 的工具包。 使用django-rest-framework實現(xiàn)前后分離。

rest總結目錄

  1. 安裝與配置
  2. 模型定義
  3. 路由
  4. 視圖
  5. 序列化
  6. 條件過濾
  7. 增刪改查方法自定義
  8. to_representation方法
  9. get_queryset方法
  10. get_object方法

1. 安裝與配置

??安裝djangorestframework

pip install djangorestframework==3.4.6

??安裝過濾

pip install django-filter

??配置settings.py文件

??在工程目錄中的settings.py文件的INSTALLED_APPS中需要添加rest_framework

INSTALLED_APPS = [
    ...

    'rest_framework',
]

2. 模型定義

??定義文章模型類和文章分類的模型類,并指定分類和文章之間的一對多的關聯(lián)關系

from django.db import models

class Atype(models.Model):
    t_name = models.CharField(max_length=10)

    class Meta:
        db_table = 'a_type'


class Article(models.Model):
    title = models.CharField(max_length=10)
    desc = models.CharField(max_length=100)
    content = models.TextField()
    is_delete = models.BooleanField(default=0)
    create_time = models.DateTimeField(auto_now_add=True)
    atype = models.ForeignKey(Atype, null=True)

    class Meta:
        db_table = 'article'

3. 路由

??定義路由需要注意:

    使用router.register注冊的url為資源,而且資源只能為名詞不能為動詞。
    定義的資源不要加'/'斜杠,在訪問地址的時候,URL中會默認的添加反斜杠'/'
from django.conf.urls import url

from rest_framework.routers import SimpleRouter

# 導入應用article中的views.py文件
from article import views


# 生成路由對象
router = SimpleRouter()
# 路由管理資源art
router.register('art', views.ArticleView)

urlpatterns = [
    url(r'list/', views.list_art),
]
# router.urls生成資源對應的路由地址
# 例如地址: /art/ 、 /art/id/
urlpatterns += router.urls

4. 視圖

??定義基于類的視圖ArticleView,可以通過繼承父類來實現(xiàn)創(chuàng)建/檢索/更新/刪除等操作,而開發(fā)者只需要輕松地構造可重復使用的行為即可。而這些常見的創(chuàng)建/檢索/更新/刪除等操作是在REST框架的mixin類中實現(xiàn)的。

??如下定義基于類的視圖ArticleView,視圖中實現(xiàn)序列化類ArticleSerializer和過濾類ArticleFiler:

from rest_framework import mixins, viewsets

from article.article_filter import ArticleFiler
from article.article_serializer import ArticleSerializer
from article.models import Article


class ArticleView(viewsets.GenericViewSet,
                  mixins.ListModelMixin,
                  mixins.DestroyModelMixin,
                  mixins.CreateModelMixin,
                  mixins.UpdateModelMixin,
                  mixins.RetrieveModelMixin):
    # 查詢返回的數(shù)據(jù)
    queryset = Article.objects.filter(is_delete=0)
    # 序列化返回的文章數(shù)據(jù)
    serializer_class = ArticleSerializer
    # 過濾
    filter_class = ArticleFiler

??分析:

    queryset: 指明在查詢數(shù)據(jù)時使用的查詢集。
    serializer_class: 指明該視圖在進行序列化或反序列化時使用的序列化器。
    filter_class: 指明過濾URL中傳遞參數(shù)的過濾器。

5. 序列化

??定義序列化模型的ArticleSerializer類,并繼承于serializers.ModelSerializer。其中可以自定義序列化字段的最大長度max_length和最小長度min_length以及錯誤信息的自定義error_messages。而fields字段表示序列化后用于展示的字段。

from rest_framework import serializers

from article.models import Article


class ArticleSerializer(serializers.ModelSerializer):
    desc = serializers.CharField(min_length=10,
                                 max_length=100,
                                 error_messages={
                                     'required': '描述必填',
                                     'max_length': '描述不超過100字符',
                                     'min_length': '描述不少于10字符'
                                 })
    title = serializers.CharField(max_length=10,
                                  error_messages={
                                      'required': '標題必填',
                                  })
    content = serializers.CharField(min_length=10,
                                    error_messages={
                                      'required': '內容必填',
                                    })
    class Meta:
        # 序列化的模型
        model = Article
        # 需要序列化的字段
        fields = ['title', 'desc', 'content', 'id', 'atype']

??分析:

    model: 指明該序列化器處理的數(shù)據(jù)字段從模型類Article參考生成。
    fields: 指明該序列化器包含模型類中的哪些字段,'all'指明包含所有字段。

6. 條件過濾

??定義過濾模型的ArticleFiler類,并繼承與filters.FilterSet。如下定義過濾的字段title、desc、content、min_time、max_time,且過濾的title、desc、content為模糊搜索。

??定義如下的過濾字段,搜索的URL定義如下所示:

http://127.0.0.1/xxx/art/?title=小明&desc=django&content=學習&max_time=2018-12-12&min_time=2018-11-11。該URL表名模糊搜索標題title、desc、content,且創(chuàng)建時間大于2018-11-11且創(chuàng)建時間小于2018-12-12

from rest_framework import filters
import django_filters

from article.models import Article


class ArticleFiler(filters.FilterSet):
    # 過濾URL中title參數(shù)
    title = django_filters.CharFilter('title', lookup_expr='contains')
    # 過濾URL中的desc參數(shù)
    desc = django_filters.CharFilter('desc', lookup_expr='contains')
    # 過濾URL中的content參數(shù)
    content = django_filters.CharFilter('content', lookup_expr='contains')
    # 過濾URL中時間最小值min_time
    min_time = django_filters.DateTimeFilter('create_time', lookup_expr='gt')
    # 過濾URL中時間最大值max_time
    max_time = django_filters.DateTimeFilter('create_time', lookup_expr='lt')

    class Meta:
        model = Article
        fields = ['title', 'desc', 'content', 'create_time']

7. 增刪改查方法自定義

??mixins在djangorestframework中主要配合viewsets共同使用,實現(xiàn)http方法與mixins的相關類與方法進行關聯(lián)。djangorestframework中有5類Minxin,他們與http方法對應如下:

mixins 作用 對應的請求方式
mixins.ListModelMixin 定義一個list方法,返回一個queryset的列表 Get
mixins.CreateModelMixin 定義一個create方法,創(chuàng)建一個實例 Post
mixins.RetriverModelMixin 定義一個retrieve方法,返回一個具體的實例 Get
mixins.UpdateModelMixin 定義一個update方法,對某個實例進行更新 Put/Patch
mixins.DestoryModelMixin 定義一個delete方法,刪除某個實例 Delete

??具體分析:

7.1 CreateModelMixin

??源碼:

class CreateModelMixin(object):
    """
    Create a model instance ==>創(chuàng)建一個實例
    """
    def create(self, request, *args, **kwargs):

    # 獲取相關serializer
        serializer = self.get_serializer(data=request.data)

        # 進行serializer的驗證
        # raise_exception=True,一旦驗證不通過,不再往下執(zhí)行,直接引發(fā)異常
        serializer.is_valid(raise_exception=True)

        # 調用perform_create()方法,保存實例
        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()

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

??創(chuàng)建的邏輯思路圖如下:


drf_create.png

??分析: 由上圖可以看出這個類的一個邏輯,其中,perform_create( )對serializer直接進行save保存,當在一些情境下,我們需要對perform_create( )進行重寫。

??那么我們現(xiàn)在可能有一個下面的需要:

??假設現(xiàn)在有一個course課程model,里面維持了一個數(shù),記錄課程收藏數(shù),還存在一個用戶收藏userfav的model(外鍵course指向課程模型),當一個用戶對課程進行收藏,理論上現(xiàn)在post進來的應該是userfav的instance,顯然,我們還需要對相應course的收藏數(shù)fav_num進行+1。 這個時候,我們就需要重寫perform_create( )方法!

def perform_create(self, serializer):
    # 重寫save的邏輯
    instance = serializer.save()
    course = instance.course
    course.fav_num += 1
    course.save()

7.2 ListModelMixin

??源碼:

class ListModelMixin(object):
    """
    List a queryset.==> 列表頁獲取
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        # 這是一個分頁功能,如果在viewset中設置了pagination_class,那么這里就會起作用
        # 獲取當前頁的queryset,如果不存在分頁,返回None
        page = self.paginate_queryset(queryset)

        if page is not None:
        # 分頁不為空,那么不能簡單的執(zhí)行Response(serializer.data)
        # 還需要將相關的page信息序列化在進行響應
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

分析: ListModelMixin一般用來獲取列表頁,大多數(shù)情況下比較簡單,不需要重寫相關的方法。

7.3 RetrieveModelMixin

??源碼:

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.==> 獲取某一個對象的具體信息
    """
    def retrieve(self, request, *args, **kwargs):
        # 一般訪問的url都為/obj/id/這種新式
        # get_object()可以獲取到這個id的對象
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

??分析: 訪問的URL都為/obj/id/這種新式才會調用該retrieve方法,其中get_object()可以獲取到這個id的對象。開發(fā)中對retrieve這個方法的重寫幾率比較高,例如我們在增加點擊數(shù)的時候,經常要對其進行一個重寫。

7.4 UpdateModelMixin

??源碼:

class UpdateModelMixin(object):
    """
    Update a model instance.==> 更新某個具體對象的內容
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

??分析: UpdateModelMixin實現(xiàn)邏輯基本整合了Create以及Retrieve,先得到具體的實例,再對其進行驗證以及保存,如果需要對更新這個邏輯進行自定義,那么需要重寫perform_update( )方法,而盡量少去重寫update( )

7.5 DestroyModelMixin

??源碼:

class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

??DestroyModelMixin的邏輯也相對比較簡單,當刪除文章對象數(shù)據(jù)時,通過修改模型中的定義的is_delete字段,將is_delete字段置為1表示刪除數(shù)據(jù),這是邏輯刪除,并不是物理刪除。因此重構perform_destroy方法,如下:

def perform_destroy(self, instance):
    instance.is_delete = 1
    instance.save()

8. to_representation方法

??概念:序列化器的每個字段實際都是由該字段類型的to_representation方法決定格式的,可以通過重寫該方法來決定格式。

??如下重定義to_representation方法,把每一列數(shù)據(jù)(其中instance代表每一列數(shù)據(jù))進行修改重組,然后返回,如下示例將返回文章的類型字段進行修改再填充回數(shù)據(jù)中進行返回。

from rest_framework import serializers

from article.models import Article


class ArticleSerializer(serializers.ModelSerializer):
    desc = serializers.CharField(min_length=10,
                                 max_length=100,
                                 error_messages={
                                     'required': '描述必填',
                                     'max_length': '描述不超過100字符',
                                     'min_length': '描述不少于10字符'
                                 })
    title = serializers.CharField(max_length=10,
                                  error_messages={
                                      'required': '標題必填',
                                  })
    content = serializers.CharField(min_length=10,
                                    error_messages={
                                      'required': '內容必填',
                                    })

    class Meta:
        # 序列化的模型
        model = Article
        # 需要序列化的字段
        fields = ['title', 'desc', 'content', 'id', 'atype']

    def to_representation(self, instance):
        # 序列化是會默認調用該方法,返回的結果為當前instance對象的序列化結果
        data = super().to_representation(instance)
        if instance.atype:
            data['atype'] = instance.atype.t_name
        return data

9. get_queryset方法

??get_queryset(self):返回視圖使用的查詢集,是列表視圖與詳情視圖獲取數(shù)據(jù)的基礎,默認返回queryset屬性,可以重寫,例如對查詢結果集進行再次過濾,可以重寫如下:

def get_queryset(self):
    queryset = self.queryset
    return queryset.filter(title__contains='django學習day01')

10. get_object方法

??get_object(self): 返回詳情視圖所需的模型類數(shù)據(jù)對象。在視圖中可以調用該方法獲取詳情信息的模型類對象。若詳情訪問的模型類對象不存在,會返回404。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容