django-rest-framework,是一套基于Django 的 REST 框架,是一個強大靈活的構建 Web API 的工具包。 使用django-rest-framework實現(xiàn)前后分離。
rest總結目錄
- 安裝與配置
- 模型定義
- 路由
- 視圖
- 序列化
- 條件過濾
- 增刪改查方法自定義
- to_representation方法
- get_queryset方法
- 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)建的邏輯思路圖如下:

??分析: 由上圖可以看出這個類的一個邏輯,其中,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。