Django - RESTful使用指南
按照 Django 的常規(guī)方法當(dāng)然也可以實現(xiàn)REST,但有一種更快捷、強(qiáng)大的方法,那就是 Django REST framework.它是python的一個模塊,通過在 Django 里面配置就可以把 app 的 models 中的各個表實現(xiàn) RESTful API。具體實現(xiàn)方法如下:
安裝配置
# 實現(xiàn)restful的模塊
pip install djangorestframework==3.4.6
# 實現(xiàn)restful過濾功能的模塊
pip install django-filter
注意:這里使用的是3.4.6版本的 djangorestframework ,不同版本之間的 djangorestframework 有所不同,可以故意打錯版本號來查看 djangoframework 來查看有哪些版本。
安裝完畢以上兩個模塊后,還需要將 rest_framework 作為 APP 添加到 settings.py 文件中。
INSTALLED_APPS = [
....
'rest_framework',
]
創(chuàng)建model
在 stu APP中創(chuàng)建兩張表,學(xué)生表和學(xué)生拓展信息表:
from django.db import models
# Create your models here.
class Student(models.Model):
s_name = models.CharField(max_length=10)
s_tel = models.CharField(max_length=11)
class Meta:
db_table = 'stu'
class StudentInfo(models.Model):
i_addr = models.CharField(max_length=50)
sid = models.OneToOneField(Student)
class Meta:
db_table = 'stu_info'
創(chuàng)建序列化類(Serializer)
創(chuàng)建序列化類的作用就是從你傳入的參數(shù)中提取出你需要的數(shù)據(jù),并把它轉(zhuǎn)化為 json 格式返回。這里在stu文件夾下創(chuàng)建serializers.py,并添加如下內(nèi)容:
from rest_framework import serializers
from stu.models import Student
class studentserializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ['id', 's_name', 's_tel']
def to_representation(self, instance):
data = super().to_representation(instance)
try:
data['i_addr'] = instance.studentinfo.i_addr
except:
data['i_addr'] = ''
return data
添加url路由
創(chuàng)建一個能夠獲取學(xué)生模型中數(shù)據(jù)的 API 接口路由:
from django.conf.urls import url
from rest_framework.routers import SimpleRouter
from stu import views
# 創(chuàng)建一個一個Simplerouter對象
routers = SimpleRouter()
# 注冊獲取數(shù)據(jù)的API接口路由,執(zhí)行的視圖為'views.showallstu'
routers.register(r'student', views.showallstu)
urlpatterns = []
# 將注冊路由添加到django路由系統(tǒng)中
urlpatterns += routers.urls
url視圖處理
對于普通的url請求我們是在views.py中定義的一個函數(shù),但是對于RESTful是定義一個類,定義的showallstu類如下:
from django.shortcuts import render
from rest_framework import mixins, viewsets
# Create your views here.
from stu.models import Student
from stu.serializers import studentserializer
class showallstu(mixins.CreateModelMixin, # 用于創(chuàng)建數(shù)據(jù)
mixins.DestroyModelMixin, # 用于刪除數(shù)據(jù)
mixins.UpdateModelMixin, # 用于更新數(shù)據(jù)
mixins.RetrieveModelMixin, # 用于顯示單個數(shù)據(jù)
mixins.ListModelMixin, # 用于顯示所有數(shù)據(jù)
viewsets.GenericViewSet):
# 設(shè)置要返回的內(nèi)容queryset
queryset = Student.objects.all()
# 指定序列化類,將返回的內(nèi)容序列化為json格式
serializer_class = studentserializer
到這里一個支持對學(xué)生表進(jìn)行增、刪、查、改的數(shù)據(jù)接口就做好了,我們可以使用接口調(diào)試神器POSTMAN來進(jìn)行測試。
結(jié)果如下圖:

<hr />
其他
自定義返回的json格式
通常對于一個請求,無論是否成功,我們都應(yīng)該返回一些東西來告知其請求的結(jié)果,對于上面的這種如果沒有數(shù)據(jù),那么返回的便是一個空列表,因此我們需要自定義JSONRenderer。
自定義JSONRenderer的方法很簡單,通過創(chuàng)建一個類去繼承JSONRenderer,并重構(gòu)其render方法,然后在settings.py文件中修改默認(rèn)使用的renderer類為我們自定義的類即可。
在項目目錄下創(chuàng)建文件夾utils,在utils目錄下創(chuàng)建rendererresponse.py文件,添加如下代碼自定義返回的json數(shù)據(jù):
# 導(dǎo)入控制返回的JSON格式的類
from rest_framework.renderers import JSONRenderer
class customrenderer(JSONRenderer):
# 重構(gòu)render方法
def render(self, data, accepted_media_type=None, renderer_context=None):
if renderer_context:
# 獲取需要返回的msg和code信息,沒有則賦值
if isinstance(data, dict):
msg = data.pop('msg', '請求成功')
code = data.pop('code', 0)
else:
msg = '請求成功'
code = 0
# 重新構(gòu)建返回的JSON字典
ret = {
'msg': msg,
'code': code,
'data': data,
}
# 返回JSON數(shù)據(jù)
return super().render(ret, accepted_media_type, renderer_context)
else:
return super().render(data, accepted_media_type, renderer_context)
settings.py文件中,修改默認(rèn)renderer類:
REST_FRAMEWORK = {
# 修改默認(rèn)返回JSON的renderer的類
'DEFAULT_RENDERER_CLASSES': (
'utils.rendererresponse.customrenderer',
),
}
返回的json數(shù)據(jù)格式為:
異常處理
自定義異常處理,一定需要繼承from rest_framework.exceptions import APIException 中的APIException,在編寫自己的異常處理的方法:

空值處理
除了對異常錯誤的處理之外,我們還要對傳入數(shù)據(jù)是否是空值做處理。因為傳入空值服務(wù)器會返回錯誤,如下圖:
如上圖,如果傳入的數(shù)據(jù)時空值的話,那么服務(wù)器就會返回一個 "This field may not be blank." 的報錯。這時候我們需要在serializer中定義s_name的序列化,指定錯誤的信息,為空的話,提示響應(yīng)的錯誤信息。
實現(xiàn)分頁
通常用戶獲取的數(shù)據(jù)可能是有很多條的,我們是不可能所有的數(shù)據(jù)一起返回給用戶的,明顯那是不理智的,所以我們還需要對返回的數(shù)據(jù)做分頁處理。
用 restful 實現(xiàn)分頁很簡單,只需要在settings.py中設(shè)置默認(rèn)分頁的類和分頁的每頁顯示的條數(shù)即可:
REST_FRAMEWORK = {
# 自定義返回的json格式
'DEFAULT_RENDERER_CLASSES': (
'utils.rendererresponse.customrenderer',
),
# 設(shè)置分頁(固定表達(dá)式)
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
# 設(shè)置分頁每頁顯示的信息數(shù)
'PAGE_SIZE': 3,
}
分頁后效果:

注意: ' count ' 表示總存在的信息的條數(shù), ' next '表示下一頁的地址,' pervious ' 表示上一頁的地址,null表示沒有上一頁??梢酝ㄟ^這幾個參數(shù)知道是否還有下一頁上一頁。
數(shù)據(jù)過濾
通常在用戶進(jìn)行搜索和獲取數(shù)據(jù)的時候都需要對數(shù)據(jù)進(jìn)行過濾,在 restful 中要實現(xiàn)數(shù)據(jù)的過濾其實也很簡單。先創(chuàng)建一個數(shù)據(jù)過濾的類,將可能用到的過濾方法都放到這個類下面,然后修改settings.py文件,添加默認(rèn)過濾規(guī)則,然后修改視圖函數(shù)指定過濾的類。
1.創(chuàng)建過濾的類
在utils目錄下創(chuàng)建filters.py文件,并添加如下內(nèi)容:
import django_filters
from rest_framework import filters
from stu.models import Student
class studentfilter(filters.FilterSet):
# 表示以模糊搜索student表s_name中包含傳入的name參數(shù)中的數(shù)據(jù)
name = django_filters.CharFilter('s_name', lookup_expr='icontains')
# 在s_tel字段中精確搜索傳過來的tel參數(shù)的值,返回符合條件的結(jié)果
tel = django_filters.CharFilter('s_tel')
# 范圍搜索
max_yuwen = django_filters.NumberFilter('s_yuwen', lookup_expr='lte')
min_yuwen = django_filters.NumberFilter('s_yuwen', lookup_expr='gte')
class Meta:
model = Student
fields = ['id', 's_name', 's_tel', 's_yuwen']
2.修改配置文件
修改settings.py配置,設(shè)置默認(rèn)過濾規(guī)則:
REST_FRAMEWORK = {
# 設(shè)置過濾(固定寫法)
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',),
}
注意:在修改配置文件或者重構(gòu)rest_framework的這些操作的時候,一定要注意單詞拼寫一定要正確,這些很多都是固定寫法,如果寫錯了就可能導(dǎo)致不能運行出想要的結(jié)果。
3.修改視圖文件
修改視圖處理類,為其制定默認(rèn)過濾的類,也可以指定排序規(guī)則:
from django.shortcuts import render
from rest_framework import mixins, viewsets
# Create your views here.
from stu.models import Student
from stu.serializers import studentserializer
from utils.filters import studentfilter
class showallstu(mixins.CreateModelMixin,
mixins.DestroyModelMixin,
mixins.UpdateModelMixin,
mixins.RetrieveModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
queryset = Student.objects.all()
# 定義序列化的類
serializer_class = studentserializer
# 定義過濾的類
filter_class = studentfilter
# 指定排序規(guī)則
def get_queryset(self):
query = self.queryset
return query.order_by('-id')
練習(xí):
1.查名字中包含王的學(xué)習(xí)信息:
http://127.0.0.1:8000/stu/student/?name=王
2.查找電話號碼為911的學(xué)生信息:
http://127.0.0.1:8000/stu/student/?tel=911

3.查找語文成績小于60的所有學(xué)生信息:
http://127.0.0.1:8000/stu/student/?max_yuwen=60
4.查找語文成績在70到90之間的學(xué)生信息:
http://127.0.0.1:8000/stu/student/?min_yuwen=70&max_yuwen=90

5.查找語文成績在70到90之間并姓王的學(xué)生信息:
http://127.0.0.1:8000/stu/student/?name=王&min_yuwen=70&max_yuwen=90