目錄
- 1. DjangoRESTframework
- 1.1 web應用模式
- 1 前后端不分離
- 2 前后端分離
- 1.1 認識RESTful
- 1.2 使用Django開發REST 介面
- 1.3 Django REST framework 簡介
- 1.1 web應用模式
- 2. DRF工程搭建
- 2.1 環境安裝與配置
- 2.2 使用
- 3. Serializer序列化器
- 3.1 定義Serializer
- 1. 定義方法
- 2. 欄位與選項
- 通用引數:
- 3. 創建Serializer物件
- 3.2 序列化使用
- 1 基本使用
- 2 關聯物件嵌套序列化
- 1) PrimaryKeyRelatedField
- 2) StringRelatedField
- 3)使用關聯物件的序列化器
- many引數
- 3.3 反序列化使用
- 1. 驗證
- 1)validate_
- 2)validate
- 3)validators
- 1)validate_
- 2. 保存
- 說明:
- 1. 驗證
- 3.4 模型類序列化器ModelSerializer
- 1. 定義
- 2. 指定欄位
- 3. 添加額外引數
- 3.1 定義Serializer
- 4. 視圖
- 4.1 Request 與 Response
- 1. Request
- 常用屬性
- 1).data
- 2).query_params
- 2. Response
- 構造方式
- 3. 狀態碼
- 1)資訊告知 - 1xx
- 2)成功 - 2xx
- 3)重定向 - 3xx
- 4)客戶端錯誤 - 4xx
- 5)服務器錯誤 - 5xx
- 4.2 視圖概覽
- 4.3 視圖說明
- 1. 兩個基類
- 1)APIView
- 支持定義的屬性:
- 2)GenericAPIView
- 支持定義的屬性:
- 提供的方法:
- get_serializer(self, *args, **kwargs)
- 1)APIView
- 2. 五個擴展類
- 1)ListModelMixin
- 2)CreateModelMixin
- 3) RetrieveModelMixin
- 4)UpdateModelMixin
- 5)DestroyModelMixin
- 3. 幾個可用子類視圖
- 1) CreateAPIView
- 2)ListAPIView
- 3)RetireveAPIView
- 4)DestoryAPIView
- 5)UpdateAPIView
- 6)RetrieveUpdateAPIView
- 7)RetrieveUpdateDestoryAPIView
- 1. 兩個基類
- 4.4 視圖集ViewSet
- 1. action屬性
- 2. 常用視圖集父類
- 1) ViewSet
- 2)GenericViewSet
- 3)ModelViewSet
- 4)ReadOnlyModelViewSet
- 3. 視圖集中定義附加action動作
- 4. 視圖集的繼承關系
- 4.5 路由Routers
- 1. 使用方法
- 2. 視圖集中包含附加action的
- 3. 路由router形成URL的方式
- 4.1 Request 與 Response
- 5. 其他功能
- 5.1 版本
- 5.2 認證Authentication
- 5.3 權限Permissions
- 使用
- 提供的權限
- 舉例
- 5.4 限流Throttling
- 使用
- 可選限流類
- 實體
- 5.5 過濾Filtering
- 5.6 排序
- 使用方法:
- 5.7 分頁Pagination
- 可選分頁器
- 1) PageNumberPagination
- 2)LimitOffsetPagination
- 可選分頁器
- 5.78 例外處理 Exceptions
- REST framework定義的例外
- 5.9 自動生成介面檔案
- 1. 安裝依賴
- 2. 設定介面檔案訪問路徑
- 3. 檔案描述說明的定義位置
- 4. 訪問介面檔案網頁
- 兩點說明:
- 5.10 JWT
- 1 介紹
- 2 安裝
- 3 案例
- 5.11 跨域
- 1 解決跨域:CORS
- 2 跨域時,發送了2次請求?
- 3 總結
- 5.12 paramiko
1. DjangoRESTframework
1.1 web應用模式
在開發Web應用中,有兩種應用模式:
- 前后端不分離
- 前后端分離
1 前后端不分離

在前后端不分離的應用模式中,前端頁面看到的效果都是由后端控制,由后端渲染頁面或重定向,也就是后端需要控制前端的展示,前端與后端的耦合度很高,
這種應用模式比較適合純網頁應用,但是當后端對接App時,App可能并不需要后端回傳一個HTML網頁,而僅僅是資料本身,所以后端原本回傳網頁的介面不再適用于前端App應用,為了對接App后端還需再開發一套介面,
2 前后端分離

在前后端分離的應用模式中,后端僅回傳前端所需的資料,不再渲染HTML頁面,不再控制前端的效果,至于前端用戶看到什么效果,從后端請求的資料如何加載到前端中,都由前端自己決定,網頁有網頁的處理方式,App有App的處理方式,但無論哪種前端,所需的資料基本相同,后端僅需開發一套邏輯對外提供資料即可,
在前后端分離的應用模式中 ,前端與后端的耦合度相對較低,
在前后端分離的應用模式中,我們通常將后端開發的每個視圖都稱為一個介面,或者API,前端通過訪問介面來對資料進行增刪改查,
1.1 認識RESTful
1.給別人提供一個URL,根據URL請求方式的不同,做不同操作,
get,獲取
post,增加
put,全部更新
patch,區域更新
delete,洗掉
2.資料傳輸基于json格式,
1.2 使用Django開發REST 介面
Django框架中使用的圖書英雄案例來寫一套支持圖書資料增刪改查的REST API介面,
在此案例中,前后端均發送JSON格式資料,
# models
from django.db import models
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名稱')
bpub_date = models.DateField(verbose_name='發布日期', null=True)
bread = models.IntegerField(default=0, verbose_name='閱讀量')
bcomment = models.IntegerField(default=0, verbose_name='評論量')
image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
# urls.py
urlpatterns = [
url(r'^books/$', views.BooksAPIVIew.as_view()),
url(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view())
]
# views.py
from datetime import datetime
class BooksAPIVIew(View):
"""
查詢所有圖書、增加圖書
"""
def get(self, request):
"""
查詢所有圖書
路由:GET /books/
"""
queryset = BookInfo.objects.all()
book_list = []
for book in queryset:
book_list.append({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image.url if book.image else ''
})
return JsonResponse(book_list, safe=False)
def post(self, request):
"""
新增圖書
路由:POST /books/
"""
json_bytes = request.body
json_str = json_bytes.decode()
book_dict = json.loads(json_str)
# 此處詳細的校驗引數省略
book = BookInfo.objects.create(
btitle=book_dict.get('btitle'),
bpub_date=datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date()
)
return JsonResponse({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image if book.image else ''
}, status=201)
class BookAPIView(View):
def get(self, request, pk):
"""
獲取單個圖書資訊
路由: GET /books/<pk>/
"""
try:
book = BookInfo.objects.get(pk=pk)
except BookInfo.DoesNotExist:
return HttpResponse(status=404)
return JsonResponse({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image.url if book.image else ''
})
def put(self, request, pk):
"""
修改圖書資訊
路由: PUT /books/<pk>
"""
try:
book = BookInfo.objects.get(pk=pk)
except BookInfo.DoesNotExist:
return HttpResponse(status=404)
json_bytes = request.body
json_str = json_bytes.decode()
book_dict = json.loads(json_str)
# 此處詳細的校驗引數省略
book.btitle = book_dict.get('btitle')
book.bpub_date = datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date()
book.save()
return JsonResponse({
'id': book.id,
'btitle': book.btitle,
'bpub_date': book.bpub_date,
'bread': book.bread,
'bcomment': book.bcomment,
'image': book.image.url if book.image else ''
})
def delete(self, request, pk):
"""
洗掉圖書
路由: DELETE /books/<pk>/
"""
try:
book = BookInfo.objects.get(pk=pk)
except BookInfo.DoesNotExist:
return HttpResponse(status=404)
book.delete()
return HttpResponse(status=204)
使用Postman測驗上述介面
1) 獲取所有圖書資料
GET 方式訪問 http://127.0.0.1:8000/books/, 回傳狀態碼200,資料如下
[
{
"id": 1,
"btitle": "射雕英雄傳",
"bpub_date": "1980-05-01",
"bread": 12,
"bcomment": 34,
"image": ""
},
{
"id": 2,
"btitle": "天龍八部",
"bpub_date": "1986-07-24",
"bread": 36,
"bcomment": 40,
"image": ""
}
]
2)獲取單一圖書資料
GET 訪問 http://127.0.0.1:8000/books/5/ ,回傳狀態碼200, 資料如下
{
"id": 5,
"btitle": "西游記",
"bpub_date": "1988-01-01",
"bread": 10,
"bcomment": 10,
"image": "booktest/xiyouji.png"
}
3)新增圖書資料
POST 訪問http://127.0.0.1:8000/books/,發送JSON資料:
{
"btitle": "三國演義",
"bpub_date": "1990-02-03"
}
回傳狀態碼201,資料如下
{
"id": 8,
"btitle": "三國演義",
"bpub_date": "1990-02-03",
"bread": 0,
"bcomment": 0,
"image": ""
}
4)修改圖書資料
PUT 訪問http://127.0.0.1:8000/books/8/,發送JSON資料:
{
"btitle": "三國演義(第二版)",
"bpub_date": "1990-02-03"
}
回傳狀態碼200,資料如下
{
"id": 8,
"btitle": "三國演義(第二版)",
"bpub_date": "1990-02-03",
"bread": 0,
"bcomment": 0,
"image": ""
}
5)洗掉圖書資料
DELETE 訪問http://127.0.0.1:8000/books/8/,回傳204狀態碼
1.3 Django REST framework 簡介
- 在序列化與反序列化時,雖然操作的資料不盡相同,但是執行的程序卻是相似的,也就是說這部分代碼是可以復用簡化撰寫的,
- 在開發REST API的視圖中,雖然每個視圖具體操作的資料不同,但增、刪、改、查的實作流程基本套路化,所以這部分代碼也是可以復用簡化撰寫的:
- 增:校驗請求資料 -> 執行反序列化程序 -> 保存資料庫 -> 將保存的物件序列化并回傳
- 刪:判斷要洗掉的資料是否存在 -> 執行資料庫洗掉
- 改:判斷要修改的資料是否存在 -> 校驗請求的資料 -> 執行反序列化程序 -> 保存資料庫 -> 將保存的物件序列化并回傳
- 查:查詢資料庫 -> 將資料序列化并回傳
2. DRF工程搭建
記憶:請求到來之后,先執行視圖的dispatch方法,
免除csrf認證
1. 視圖(APIView、ListAPIView、ListModelMinx)
2. 版本處理
3. 認證
4. 權限
5. 節流(頻率限制)
6. 決議器
7. 篩選器
8. 分頁
9. 序列化
10. 渲染
2.1 環境安裝與配置
DRF需要以下依賴:
- Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
- Django (1.10, 1.11, 2.0)
DRF是以Django擴展應用的方式提供的
pip install djangorestframework -i https:
//pypi.douban.com/simple/
2.2 使用
-
注冊:在settings.py的INSTALLED_APPS中添加'rest_framework',
INSTALLED_APPS = [ 'rest_framework' ]
3. Serializer序列化器
序列化器的作用:
- 進行資料的校驗
- 對資料物件進行轉換
3.1 定義Serializer
1. 定義方法
繼承自rest_framework.serializers.Serializer,
資料庫模型類BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名稱')
bpub_date = models.DateField(verbose_name='發布日期', null=True)
bread = models.IntegerField(default=0, verbose_name='閱讀量')
bcomment = models.IntegerField(default=0, verbose_name='評論量')
image = models.ImageField(upload_to='booktest', verbose_name='圖片', null=True)
我們想為這個模型類提供一個序列化器,可以定義如下:
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
注意:serializer不是只能為資料庫模型類定義,也可以為非資料庫模型類的資料定義,serializer是獨立于資料庫之外的存在,
2. 欄位與選項
常用欄位型別:
| 欄位 | 欄位構造方式 |
|---|---|
| BooleanField | BooleanField() |
| NullBooleanField | NullBooleanField() |
| CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
| EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
| RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
| SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正則欄位,驗證正則模式 [a-zA-Z0-9-]+ |
| URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
| UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
| IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
| IntegerField | IntegerField(max_value=https://www.cnblogs.com/LYPZX/p/None, min_value=None) |
| FloatField | FloatField(max_value=https://www.cnblogs.com/LYPZX/p/None, min_value=None) |
| DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=https://www.cnblogs.com/LYPZX/p/None, min_value=None) max_digits: 最多位數 decimal_palces: 小數點位置 |
| DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
| DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
| TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
| DurationField | DurationField() |
| ChoiceField | ChoiceField(choices) choices與Django的用法相同 |
| MultipleChoiceField | MultipleChoiceField(choices) |
| FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| ListField | ListField(child=, min_length=None, max_length=None) |
| DictField | DictField(child=) |
選項引數:
| 引數名稱 | 作用 |
|---|---|
| max_length | 最大長度 |
| min_lenght | 最小長度 |
| allow_blank | 是否允許為空 |
| trim_whitespace | 是否截斷空白字符 |
| max_value | 最小值 |
| min_value | 最大值 |
通用引數:
| 引數名稱 | 說明 |
|---|---|
| read_only | 表明該欄位僅用于序列化輸出,默認False |
| write_only | 表明該欄位僅用于反序列化輸入,默認False |
| required | 表明該欄位在反序列化時必須輸入,默認True |
| default | 反序列化時使用的默認值 |
| allow_null | 表明該欄位是否允許傳入None,默認False |
| validators | 該欄位使用的驗證器 |
| error_messages | 包含錯誤編號與錯誤資訊的字典 |
| label | 用于HTML展示API頁面時,顯示的欄位名稱 |
| help_text | 用于HTML展示API頁面時,顯示的欄位幫助提示資訊 |
3. 創建Serializer物件
定義好Serializer類后,就可以創建Serializer物件了,
Serializer的構造方法為:
Serializer(instance=None, data=https://www.cnblogs.com/LYPZX/p/empty, **kwarg)
說明:
1)用于序列化時,將模型類物件傳入instance引數
2)用于反序列化時,將要被反序列化的資料傳入data引數
3)除了instance和data引數外,在構造Serializer物件時,還可通過context引數額外添加資料,如
serializer = AccountSerializer(account, context={'request': request})
通過context引數附加的資料,可以通過Serializer物件的context屬性獲取,
3.2 序列化使用
我們在django shell中來學習序列化器的使用,
python manage.py shell
1 基本使用
1) 先查詢出一個圖書物件
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
2) 構造序列化器物件
from booktest.serializers import BookInfoSerializer
serializer = BookInfoSerializer(book)
3)獲取序列化資料
通過data屬性可以獲取序列化后的資料
serializer.data
# {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None}
4)如果要被序列化的是包含多條資料的查詢集QuerySet,可以通過添加many=True引數補充說明
book_qs = BookInfo.objects.all()
serializer = BookInfoSerializer(book_qs, many=True)
serializer.data
# [OrderedDict([('id', 2), ('btitle', '天龍八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', N]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image'ne)]), OrderedDict([('id', 4), ('btitle', '雪山飛狐'), ('bpub_date', '1987-11-11'), ('bread', 58), ('bcomment', 24), ('ima None)]), OrderedDict([('id', 5), ('btitle', '西游記'), ('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10), ('im', 'booktest/xiyouji.png')])]
2 關聯物件嵌套序列化
如果需要序列化的資料中包含有其他關聯物件,則對關聯物件資料的序列化需要指明,
例如,在定義英雄資料的序列化器時,外鍵hbook(即所屬的圖書)欄位如何序列化?
我們先定義HeroInfoSerialzier除外鍵欄位外的其他部分:
class HeroInfoSerializer(serializers.Serializer):
"""英雄資料序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性別', required=False)
hcomment = serializers.CharField(label='描述資訊', max_length=200, required=False, allow_null=True)
對于關聯欄位,可以采用以下幾種方式:
1) PrimaryKeyRelatedField
此欄位將被序列化為關聯物件的主鍵,
hbook = serializers.PrimaryKeyRelatedField(label='圖書', read_only=True)
指明欄位時需要包含read_only=True或者queryset引數:
- 包含read_only=True引數時,該欄位將不能用作反序列化使用
使用效果:
from booktest.serializers import HeroInfoSerializer
from booktest.models import HeroInfo
hero = HeroInfo.objects.get(id=6)
serializer = HeroInfoSerializer(hero)
serializer.data
# {'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': 2}
2) StringRelatedField
此欄位將被序列化為關聯物件的字串表示方式(即__str__方法的回傳值)
hbook = serializers.StringRelatedField(label='圖書')
使用效果
{'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': '天龍八部'}
3)使用關聯物件的序列化器
hbook = BookInfoSerializer()
使用效果
{'id': 6, 'hname': '喬峰', 'hgender': 1, 'hcomment': '降龍十八掌', 'hbook': OrderedDict([('id', 2), ('btitle', '天龍八部')te', '1986-07-24'), ('bread', 36), ('bcomment', 40), ('image', None)])}
many引數
如果關聯的物件資料不是只有一個,而是包含多個資料,如想序列化圖書BookInfo資料,每個BookInfo物件關聯的英雄HeroInfo物件可能有多個,此時關聯欄位型別的指明仍可使用上述幾種方式,只是在宣告關聯欄位時,多補充一個many=True引數即可,
此處僅拿PrimaryKeyRelatedField型別來舉例,其他相同,
在BookInfoSerializer中添加關聯欄位:
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # 新增
使用效果:
from booktest.serializers import BookInfoSerializer
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
# {'id': 2, 'btitle': '天龍八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40, 'image': None, 'heroinfo_set': [6,8, 9]}
3.3 反序列化使用
1. 驗證
使用序列化器進行反序列化時,需要對資料進行驗證后,才能獲取驗證成功的資料或保存成模型類物件,
在獲取反序列化的資料前,必須呼叫is_valid()方法進行驗證,驗證成功回傳True,否則回傳False,
驗證失敗,可以通過序列化器物件的errors屬性獲取錯誤資訊,回傳字典,包含了欄位和欄位的錯誤,如果是非欄位錯誤,可以通過修改REST framework配置中的NON_FIELD_ERRORS_KEY來控制錯誤字典中的鍵名,
驗證成功,可以通過序列化器物件的validated_data屬性獲取資料,
在定義序列化器時,指明每個欄位的序列化型別和選項引數,本身就是一種驗證行為,
如我們前面定義過的BookInfoSerializer
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20)
bpub_date = serializers.DateField(label='發布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
通過構造序列化器物件,并將要反序列化的資料傳遞給data構造引數,進而進行驗證
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/LYPZX/p/{'bpub_date': 123}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/LYPZX/p/data)
serializer.is_valid() # 回傳False
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data # {}
data = https://www.cnblogs.com/LYPZX/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/LYPZX/p/data)
serializer.is_valid() # True
serializer.errors # {}
serializer.validated_data # OrderedDict([('btitle', 'python')])
is_valid()方法還可以在驗證失敗時拋出例外serializers.ValidationError,可以通過傳遞raise_exception=True引數開啟,REST framework接收到此例外,會向前端回傳HTTP 400 Bad Request回應,
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
如果覺得這些還不夠,需要再補充定義驗證行為,可以使用以下三種方法:
1)validate_<field_name>
對<field_name>欄位進行驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def validate_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關于Django的")
return value
測驗
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/LYPZX/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/LYPZX/p/data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關于Django的', code='invalid')]}
2)validate
在序列化器中需要同時對多個欄位進行比較驗證時,可以定義validate方法來驗證,如
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('閱讀量小于評論量')
return attrs
測驗
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/LYPZX/p/{'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=https://www.cnblogs.com/LYPZX/p/data)
s.is_valid() # False
s.errors
# {'non_field_errors': [ErrorDetail(string='閱讀量小于評論量', code='invalid')]}
3)validators
在欄位中添加validators選項引數,也可以補充驗證行為,如
def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("圖書不是關于Django的")
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名稱', max_length=20, validators=[about_django])
bpub_date = serializers.DateField(label='發布日期', required=False)
bread = serializers.IntegerField(label='閱讀量', required=False)
bcomment = serializers.IntegerField(label='評論量', required=False)
image = serializers.ImageField(label='圖片', required=False)
測驗:
from booktest.serializers import BookInfoSerializer
data = https://www.cnblogs.com/LYPZX/p/{'btitle': 'python'}
serializer = BookInfoSerializer(data=https://www.cnblogs.com/LYPZX/p/data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='圖書不是關于Django的', code='invalid')]}
2. 保存
如果在驗證成功后,想要基于validated_data完成資料物件的創建,可以通過實作create()和update()兩個方法來實作,
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo(**validated_data)
def update(self, instance, validated_data):
"""更新,instance為要更新的物件實體"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
return instance
如果需要在回傳資料物件的時候,也將資料保存到資料庫中,則可以進行如下修改
class BookInfoSerializer(serializers.Serializer):
"""圖書資料序列化器"""
...
def create(self, validated_data):
"""新建"""
return BookInfo.objects.create(**validated_data)
def update(self, instance, validated_data):
"""更新,instance為要更新的物件實體"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
instance.save()
return instance
實作了上述兩個方法后,在反序列化資料的時候,就可以通過save()方法回傳一個資料物件實體了
book = serializer.save()
如果創建序列化器物件的時候,沒有傳遞instance實體,則呼叫save()方法的時候,create()被呼叫,相反,如果傳遞了instance實體,則呼叫save()方法的時候,update()被呼叫,
from db.serializers import BookInfoSerializer
data = https://www.cnblogs.com/LYPZX/p/{'btitle': '封神演義'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 封神演義>
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = https://www.cnblogs.com/LYPZX/p/{'btitle': '倚天劍'}
serializer = BookInfoSerializer(book, data=https://www.cnblogs.com/LYPZX/p/data)
serializer.is_valid() # True
serializer.save() #
book.btitle #'倚天劍'
說明:
1) 在對序列化器進行save()保存時,可以額外傳遞資料,這些資料可以在create()和update()中的validated_data引數獲取到
serializer.save(owner=request.user)
3.4 模型類序列化器ModelSerializer
如果我們想要使用序列化器對應的是Django的模型類,DRF為我們提供了ModelSerializer模型類序列化器來幫助我們快速創建一個Serializer類,
ModelSerializer與常規的Serializer相同,但提供了:
- 基于模型類自動生成一系列欄位
- 基于模型類自動為Serializer生成validators,比如unique_together
- 包含默認的create()和update()的實作
1. 定義
比如我們創建一個BookInfoSerializer:
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = '__all__'
- model 指明參照哪個模型類
- fields 指明為模型類的哪些欄位生成
我們可以在python manage.py shell中查看自動生成的BookInfoSerializer的具體實作
>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
id = IntegerField(label='ID', read_only=True)
btitle = CharField(label='名稱', max_length=20)
bpub_date = DateField(allow_null=True, label='發布日期', required=False)
bread = IntegerField(label='閱讀量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=-2147483648, required=False)
bcomment = IntegerField(label='評論量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=-2147483648, required=False)
image = ImageField(allow_null=True, label='圖片', max_length=100, required=False)
2. 指定欄位
'''
model=對應的模型
fields=('參與序列化和反序列的欄位1','參與序列化和反序列的欄位2')
fields='__all__' 包含所有欄位
exclude = ('id', 'is_delete') 刨除某些欄位
read_only_fields 只能讀,不能寫
跨表自動深度3種方式(展示外鍵表的所有欄位)
depth = 1 最大10
# required = False 不是必填傳值
category_txt = serializers.CharField(source='category.name', required=False)
x1 = serializers.SerializerMethodField()
def get_x1(self, obj):
return obj.category.name
顯示:洗掉和發布文字兩種方式 (1, '發布'),(2, '洗掉')
serializers.CharField(source='get_status_display', required=False)
'''
- 使用fields來明確欄位,
__all__表名包含所有欄位,也可以寫明具體哪些欄位,如
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
- 使用exclude可以明確排除掉哪些欄位
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
exclude = ('image',)
- 顯示指明欄位,如:
class HeroInfoSerializer(serializers.ModelSerializer):
hbook = BookInfoSerializer()
class Meta:
model = HeroInfo
fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
- 指明只讀欄位
可以通過read_only_fields指明只讀欄位,即僅用于序列化輸出的欄位
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
3. 添加額外引數
我們可以使用extra_kwargs引數為ModelSerializer添加或修改原有的選項引數
class BookInfoSerializer(serializers.ModelSerializer):
"""圖書資料序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
extra_kwargs = {
'bread': {'min_value': 0, 'required': True},
'bcomment': {'min_value': 0, 'required': True},
}
# BookInfoSerializer():
# id = IntegerField(label='ID', read_only=True)
# btitle = CharField(label='名稱', max_length=20)
# bpub_date = DateField(allow_null=True, label='發布日期', required=False)
# bread = IntegerField(label='閱讀量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=0, required=True)
# bcomment = IntegerField(label='評論量', max_value=https://www.cnblogs.com/LYPZX/p/2147483647, min_value=0, required=True)
4. 視圖
4.1 Request 與 Response
1. Request
REST framework 傳入視圖的request物件不再是Django默認的HttpRequest物件,而是REST framework提供的擴展了HttpRequest類的Request類的物件,
REST framework 提供了Parser決議器,在接收到請求后會自動根據Content-Type指明的請求資料型別(如JSON、表單等)將請求資料進行parse決議,決議為類字典物件保存到Request物件中,
Request物件的資料是自動根據前端發送資料的格式進行決議之后的結果,
無論前端發送的哪種格式的資料,我們都可以以統一的方式讀取資料,
常用屬性
1).data
request.data 回傳決議之后的請求體資料,類似于Django中標準的request.POST和 request.FILES屬性,但提供如下特性:
- 包含了決議之后的檔案和非檔案資料
- 包含了對POST、PUT、PATCH請求方式決議后的資料
- 利用了REST framework的parsers決議器,不僅支持表單型別資料,也支持JSON資料
2).query_params
request.query_params與Django標準的request.GET相同,只是更換了更正確的名稱而已,
2. Response
rest_framework.response.Response
REST framework提供了一個回應類Response,使用該類構造回應物件時,回應的具體資料內容會被轉換(render渲染)成符合前端需求的型別,
構造方式
Response(data, status=None, template_name=None, headers=None, content_type=None)
data資料不要是render處理之后的資料,只需傳遞python的內建型別資料即可,REST framework會使用renderer渲染器處理data,
data不能是復雜結構的資料,如Django的模型類物件,對于這樣的資料我們可以使用Serializer序列化器序列化處理后(轉為了Python字典型別)再傳遞給data引數,
引數說明:
data: 為回應準備的序列化處理后的資料;status: 狀態碼,默認200;template_name: 模板名稱,如果使用HTMLRenderer時需指明;headers: 用于存放回應頭資訊的字典;content_type: 回應資料的Content-Type,通常此引數無需傳遞,REST framework會根據前端所需型別資料來設定該引數,
3. 狀態碼
為了方便設定狀態碼,REST framewrok在rest_framework.status模塊中提供了常用狀態碼常量,
1)資訊告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4)客戶端錯誤 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5)服務器錯誤 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
4.2 視圖概覽
REST framework 提供了眾多的通用視圖基類與擴展類,以簡化視圖的撰寫,
視圖的繼承關系:

視圖的方法與屬性:

4.3 視圖說明
1. 兩個基類
1)APIView
rest_framework.views.APIView
APIView是REST framework提供的所有視圖的基類,繼承自Django的View父類,
APIView與View的不同之處在于:
- 傳入到視圖方法中的是REST framework的
Request物件,而不是Django的HttpRequeset物件; - 視圖方法可以回傳REST framework的
Response物件,視圖會為回應資料設定(render)符合前端要求的格式; - 任何
APIException例外都會被捕獲到,并且處理成合適的回應資訊; - 在進行dispatch()分發前,會對請求進行身份認證、權限檢查、流量控制,
支持定義的屬性:
- authentication_classes 串列或元祖,身份認證類
- permissoin_classes 串列或元祖,權限檢查類
- throttle_classes 串列或元祖,流量控制類
在APIView中仍以常規的類視圖定義方法來實作get() 、post() 或者其他請求方式的方法,
舉例:
from rest_framework.views import APIView
from rest_framework.response import Response
# url(r'^books/$', views.BookListView.as_view()),
class BookListView(APIView):
def get(self, request):
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
return Response(serializer.data)
2)GenericAPIView
rest_framework.generics.GenericAPIView
繼承自APIVIew,增加了對于串列視圖和詳情視圖可能用到的通用支持方法,通常使用時,可搭配一個或多個Mixin擴展類,
支持定義的屬性:
- 串列視圖與詳情視圖通用:
- queryset 串列視圖的查詢集
- serializer_class 視圖使用的序列化器
- 串列視圖使用:
- pagination_class 分頁控制類
- filter_backends 過濾控制后端
- 詳情頁視圖使用:
- lookup_field 查詢單一資料庫物件時使用的條件欄位,默認為'
pk' - lookup_url_kwarg 查詢單一資料時URL中的引數關鍵字名稱,默認與look_field相同
- lookup_field 查詢單一資料庫物件時使用的條件欄位,默認為'
提供的方法:
-
串列視圖與詳情視圖通用:
-
get_queryset(self)
回傳視圖使用的查詢集,是串列視圖與詳情視圖獲取資料的基礎,默認回傳
queryset屬性,可以重寫,例如:def get_queryset(self): user = self.request.user return user.accounts.all() -
get_serializer_class(self)
回傳序列化器類,默認回傳
serializer_class,可以重寫,例如:def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer -
get_serializer(self, *args, **kwargs)
回傳序列化器物件,被其他視圖或擴展類使用,如果我們在視圖中想要獲取序列化器物件,可以直接呼叫此方法,
注意,在提供序列化器物件的時候,REST framework會向物件的context屬性補充三個資料:request、format、view,這三個資料物件可以在定義序列化器時使用,
-
-
詳情視圖使用:
-
get_object(self) 回傳詳情視圖所需的模型類資料物件,默認使用
lookup_field引數來過濾queryset, 在試圖中可以呼叫該方法獲取詳情資訊的模型類物件,若詳情訪問的模型類物件不存在,會回傳404,
該方法會默認使用APIView提供的check_object_permissions方法檢查當前物件是否有權限被訪問,
-
舉例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
book = self.get_object()
serializer = self.get_serializer(book)
return Response(serializer.data)
2. 五個擴展類
1)ListModelMixin
串列視圖擴展類,提供list(request, *args, **kwargs)方法快速實作串列視圖,回傳200狀態碼,
該Mixin的list方法會對資料進行過濾和分頁,
源代碼:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# 過濾
queryset = self.filter_queryset(self.get_queryset())
# 分頁
page = self.paginate_queryset(queryset)
if page is not None:
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)
舉例:
from rest_framework.mixins import ListModelMixin
class BookListView(ListModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request):
return self.list(request)
2)CreateModelMixin
創建視圖擴展類,提供create(request, *args, **kwargs)方法快速實作創建資源的視圖,成功回傳201狀態碼,
如果序列化器對前端發送的資料驗證失敗,回傳400錯誤,
源代碼:
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 獲取序列化器
serializer = self.get_serializer(data=https://www.cnblogs.com/LYPZX/p/request.data)
# 驗證
serializer.is_valid(raise_exception=True)
# 保存
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 {}
3) RetrieveModelMixin
詳情視圖擴展類,提供retrieve(request, *args, **kwargs)方法,可以快速實作回傳一個存在的資料物件,
如果存在,回傳200, 否則回傳404,
源代碼:
class RetrieveModelMixin(object):
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
# 獲取物件,會檢查物件的權限
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance)
return Response(serializer.data)
舉例:
class BookDetailView(RetrieveModelMixin, GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
return self.retrieve(request)
4)UpdateModelMixin
更新視圖擴展類,提供update(request, *args, **kwargs)方法,可以快速實作更新一個存在的資料物件,
同時也提供partial_update(request, *args, **kwargs)方法,可以實作區域更新,
成功回傳200,序列化器校驗資料失敗時,回傳400錯誤,
源代碼:
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=https://www.cnblogs.com/LYPZX/p/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)
5)DestroyModelMixin
洗掉視圖擴展類,提供destroy(request, *args, **kwargs)方法,可以快速實作洗掉一個存在的資料物件,
成功回傳204,不存在回傳404,
源代碼:
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()
3. 幾個可用子類視圖
1) CreateAPIView
提供 post 方法
繼承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
繼承自:GenericAPIView、ListModelMixin
3)RetireveAPIView
提供 get 方法
繼承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供 delete 方法
繼承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
繼承自:GenericAPIView、UpdateModelMixin
6)RetrieveUpdateAPIView
提供 get、put、patch方法
繼承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
繼承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
4.4 視圖集ViewSet
使用視圖集ViewSet,可以將一系列邏輯相關的動作放到一個類中:
- list() 提供一組資料
- retrieve() 提供單個資料
- create() 創建資料
- update() 保存資料
- destory() 洗掉資料
ViewSet視圖集類不再實作get()、post()等方法,而是實作動作 action 如 list() 、create() 等,
視圖集只在使用as_view()方法的時候,才會將action動作與具體請求方式對應上,如:
class BookInfoViewSet(viewsets.ViewSet):
def list(self, request):
...
def retrieve(self, request, pk=None):
...
在設定路由時,我們可以如下操作
urlpatterns = [
url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]
1. action屬性
在視圖集中,我們可以通過action物件屬性來獲取當前請求視圖集時的action動作是哪個,
例如:
def get_serializer_class(self):
if self.action == 'create':
return OrderCommitSerializer
else:
return OrderDataSerializer
2. 常用視圖集父類
1) ViewSet
繼承自APIView,作用也與APIView基本類似,提供了身份認證、權限校驗、流量管理等,
在ViewSet中,沒有提供任何動作action方法,需要我們自己實作action方法,
2)GenericViewSet
繼承自GenericAPIView,作用也與GenericAPIVIew類似,提供了get_object、get_queryset等方法便于串列視圖與詳情資訊視圖的開發,
3)ModelViewSet
繼承自GenericAPIVIew,同時包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin,
4)ReadOnlyModelViewSet
繼承自GenericAPIVIew,同時包括了ListModelMixin、RetrieveModelMixin,
3. 視圖集中定義附加action動作
在視圖集中,除了上述默認的方法動作外,還可以添加自定義動作,
添加自定義動作需要使用rest_framework.decorators.action裝飾器,
以action裝飾器裝飾的方法名會作為action動作名,與list、retrieve等同,
action裝飾器可以接收兩個引數:
-
methods: 該action支持的請求方式,串列傳遞
-
- detail
- 表示是action中要處理的是否是視圖資源的物件(即是否通過url路徑獲取主鍵)
- True 表示使用通過URL獲取的主鍵對應的資料物件
- False 表示不使用URL獲取主鍵
舉例:
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
# detail為False 表示不需要處理具體的BookInfo物件
@action(methods=['get'], detail=False)
def latest(self, request):
"""
回傳最新的圖書資訊
"""
book = BookInfo.objects.latest('id')
serializer = self.get_serializer(book)
return Response(serializer.data)
# detail為True,表示要處理具體與pk主鍵對應的BookInfo物件
@action(methods=['put'], detail=True)
def read(self, request, pk):
"""
修改圖書的閱讀量資料
"""
book = self.get_object()
book.bread = request.data.get('read')
book.save()
serializer = self.get_serializer(book)
return Response(serializer.data)
url的定義
urlpatterns = [
url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
url(r'^books/(?P<pk>\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
]
4. 視圖集的繼承關系

4.5 路由Routers
對于視圖集ViewSet,我們除了可以自己手動指明請求方式與動作action之間的對應關系外,還可以使用Routers來幫助我們快速實作路由資訊,
REST framework提供了兩個router
- SimpleRouter
- DefaultRouter
1. 使用方法
1) 創建router物件,并注冊視圖集,例如
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'books', BookInfoViewSet, base_name='book')
register(prefix, viewset, base_name)
- prefix 該視圖集的路由前綴
- viewset 視圖集
- base_name 路由名稱的前綴
如上述代碼會形成的路由如下:
^books/$ name: book-list
^books/{pk}/$ name: book-detail
2)添加路由資料
可以有兩種方式:
urlpatterns = [
...
]
urlpatterns += router.urls
或
urlpatterns = [
...
url(r'^', include(router.urls))
]
2. 視圖集中包含附加action的
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
@action(methods=['get'], detail=False)
def latest(self, request):
...
@action(methods=['put'], detail=True)
def read(self, request, pk):
...
此視圖集會形成的路由:
^books/latest/$ name: book-latest
^books/{pk}/read/$ name: book-read
3. 路由router形成URL的方式
1) SimpleRouter

2)DefaultRouter

DefaultRouter與SimpleRouter的區別是,DefaultRouter會多附帶一個默認的API根視圖,回傳一個包含所有串列視圖的超鏈接回應資料,
5. 其他功能
5.1 版本
可以在組態檔中配置全域默認的版本方案
REST_FRAMEWORK = {
# 版本配置
'DEFAULT_VERSIONING_CLASS': "rest_framework.versioning.URLPathVersioning",
"ALLOWED_VERSIONS": ['v1', 'v2'],
}
urls
from django.conf.urls import url, include
urlpatterns = [
# 版本管理
url(r'^api/(?P<version>\w+)/', include('api.urls')),
]
5.2 認證Authentication
可以在組態檔中配置全域默認的認證方案
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication', # 基本認證
'rest_framework.authentication.SessionAuthentication', # session認證
)
}
也可以在每個視圖中通過設定authentication_classess屬性來設定
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
...
認證失敗會有兩種可能的回傳值:
- 401 Unauthorized 未認證
- 403 Permission Denied 權限被禁止
5.3 權限Permissions
權限控制可以限制用戶對于視圖的訪問和對于具體資料物件的訪問,
- 在執行視圖的dispatch()方法前,會先進行視圖訪問權限的判斷
- 在通過get_object()獲取具體物件時,會進行物件訪問權限的判斷
使用
可以在組態檔中設定默認的權限管理類,如
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
如果未指明,則采用如下默認配置
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)
也可以在具體的視圖中通過permission_classes屬性來設定,如
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
...
提供的權限
- AllowAny 允許所有用戶
- IsAuthenticated 僅通過認證的用戶
- IsAdminUser 僅管理員用戶
- IsAuthenticatedOrReadOnly 認證的用戶可以完全操作,否則只能get讀取
舉例
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
5.4 限流Throttling
可以對介面訪問的頻次進行限制,以減輕服務器壓力,
如何實作的評率限制
- 匿名用戶,用IP作為用戶唯一標記,但如果用戶換代理IP,無法做到真正的限制,
- 登錄用戶,用用戶名或用戶ID做標識,
具體實作:
在django的快取中 = {
throttle_anon_1.1.1.1:[100121340,],
1.1.1.2:[100121251,100120450,]
}
限制:60s能訪問3次
來訪問時:
1.獲取當前時間 100121280
2.100121280-60 = 100121220,小于100121220所有記錄洗掉
3.判斷1分鐘以內已經訪問多少次了? 4
4.無法訪問
停一會
來訪問時:
1.獲取當前時間 100121340
2.100121340-60 = 100121280,小于100121280所有記錄洗掉
3.判斷1分鐘以內已經訪問多少次了? 0
4.可以訪問
使用
可以在組態檔中,使用DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES進行全域配置,
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day'
}
}
DEFAULT_THROTTLE_RATES 可以使用 second, minute, hour 或day來指明周期,
也可以在具體視圖中通過throttle_classess屬性來配置,如
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
throttle_classes = (UserRateThrottle,)
...
可選限流類
1) AnonRateThrottle
限制所有匿名未認證用戶,使用IP區分用戶,
使用DEFAULT_THROTTLE_RATES['anon'] 來設定頻次
2)UserRateThrottle
限制認證用戶,使用User id 來區分,
使用DEFAULT_THROTTLE_RATES['user'] 來設定頻次
3)ScopedRateThrottle
限制用戶對于每個視圖的訪問頻次,使用ip或user id,
例如:
class ContactListView(APIView):
throttle_scope = 'contacts'
...
class ContactDetailView(APIView):
throttle_scope = 'contacts'
...
class UploadView(APIView):
throttle_scope = 'uploads'
...
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.ScopedRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
'contacts': '1000/day',
'uploads': '20/day'
}
}
實體
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
throttle_classes = (UserRateThrottle,)
5.5 過濾Filtering
對于串列資料可能需要根據欄位進行過濾,我們可以通過添加django-fitlter擴展來增強支持,
pip insall django-filter
在組態檔中增加過濾后端的設定:
INSTALLED_APPS = [
...
'django_filters', # 需要注冊應用,
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
在視圖中添加filter_fields屬性,指定可以過濾的欄位
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
filter_fields = ('btitle', 'bread')
# 127.0.0.1:8000/books/?btitle=西游記
5.6 排序
對于串列資料,REST framework提供了OrderingFilter過濾器來幫助我們快速指明資料按照指定欄位進行排序,
使用方法:
在類視圖中設定filter_backends,使用rest_framework.filters.OrderingFilter過濾器,REST framework會在請求的查詢字串引數中檢查是否包含了ordering引數,如果包含了ordering引數,則按照ordering引數指明的排序欄位對資料集進行排序,
前端可以傳遞的ordering引數的可選欄位值需要在ordering_fields中指明,
示例:
class BookListView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'bread', 'bpub_date')
# 127.0.0.1:8000/books/?ordering=-bread
5.7 分頁Pagination
REST framework提供了分頁的支持,
我們可以在組態檔中設定全域的分頁方式,如:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每頁數目
}
也可通過自定義Pagination類,來為視圖添加不同分頁行為,在視圖中通過pagination_clas屬性來指明,
class LargeResultsSetPagination(PageNumberPagination):
page_size = 1000
page_size_query_param = 'page_size'
max_page_size = 10000
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
pagination_class = LargeResultsSetPagination
注意:如果在視圖內關閉分頁功能,只需在視圖內設定
pagination_class = None
可選分頁器
1) PageNumberPagination
前端訪問網址形式:
GET http://api.example.org/books/?page=4
可以在子類中定義的屬性:
- page_size 每頁數目
- page_query_param 前端發送的頁數關鍵字名,默認為"page"
- page_size_query_param 前端發送的每頁數目關鍵字名,默認為None
- max_page_size 前端最多能設定的每頁數量
基礎版 APIView
from rest_framework.pagination import PageNumberPagination
from rest_framework import serializers
class PageArticleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Article
fields = "__all__"
class PageArticleView(APIView):
def get(self,request,*args,**kwargs):
queryset = models.Article.objects.all()
# 方式一:僅資料
"""
# 分頁物件
page_object = PageNumberPagination()
# 呼叫 分頁物件.paginate_queryset方法進行分頁,得到的結果是分頁之后的資料
# result就是分完頁的一部分資料
result = page_object.paginate_queryset(queryset,request,self)
# 序列化分頁之后的資料
ser = PageArticleSerializer(instance=result,many=True)
return Response(ser.data)
"""
# 方式二:資料 + 分頁資訊
"""
page_object = PageNumberPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return page_object.get_paginated_response(ser.data)
"""
# 方式三:資料 + 部分分頁資訊
page_object = PageNumberPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return Response({'count':page_object.page.paginator.count,'result':ser.data})
優化版 ListAPIView
from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
page_size_query_param = 'page_size'
max_page_size = 10
class BookListView(ListAPIView):
queryset = BookInfo.objects.all().order_by('id')
serializer_class = BookInfoSerializer
pagination_class = StandardPageNumberPagination
# 127.0.0.1/books/?page=1&page_size=2
2)LimitOffsetPagination
前端訪問網址形式:
GET http://api.example.org/books/?limit=100&offset=400
可以在子類中定義的屬性:
- default_limit 默認限制,默認值與
PAGE_SIZE設定一直 - limit_query_param limit引數名,默認'limit'
- offset_query_param offset引數名,默認'offset'
- max_limit 最大limit限制,默認None
APIView 版
from rest_framework.pagination import PageNumberPagination
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import serializers
class PageArticleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Article
fields = "__all__"
class HulaLimitOffsetPagination(LimitOffsetPagination):
max_limit = 2
class PageArticleView(APIView):
def get(self,request,*args,**kwargs):
queryset = models.Article.objects.all()
page_object = HulaLimitOffsetPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return Response(ser.data)
ListAPIView版本
from rest_framework.pagination import LimitOffsetPagination
class BookListView(ListAPIView):
queryset = BookInfo.objects.all().order_by('id')
serializer_class = BookInfoSerializer
pagination_class = LimitOffsetPagination
# 127.0.0.1:8000/books/?offset=3&limit=2
5.78 例外處理 Exceptions
REST framework提供了例外處理,我們可以自定義例外處理函式,
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
# 先呼叫REST framework默認的例外處理方法獲得標準錯誤回應物件
response = exception_handler(exc, context)
# 在此處補充自定義的例外處理
if response is not None:
response.data['status_code'] = response.status_code
return response
在組態檔中宣告自定義的例外處理
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
如果未宣告,會采用默認的方式,如下
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
例如:
補充上處理關于資料庫的例外
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError
def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None:
view = context['view']
if isinstance(exc, DatabaseError):
print('[%s]: %s' % (view, exc))
response = Response({'detail': '服務器內部錯誤'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
return response
REST framework定義的例外
- APIException 所有例外的父類
- ParseError 決議錯誤
- AuthenticationFailed 認證失敗
- NotAuthenticated 尚未認證
- PermissionDenied 權限決絕
- NotFound 未找到
- MethodNotAllowed 請求方式不支持
- NotAcceptable 要獲取的資料格式不支持
- Throttled 超過限流次數
- ValidationError 校驗失敗
5.9 自動生成介面檔案
REST framework可以自動幫助我們生成介面檔案,
介面檔案以網頁的方式呈現,
自動介面檔案能生成的是繼承自APIView及其子類的視圖,
1. 安裝依賴
REST framewrok生成介面檔案需要coreapi庫的支持,
pip install coreapi
2. 設定介面檔案訪問路徑
在總路由中添加介面檔案路徑,
檔案路由對應的視圖配置為rest_framework.documentation.include_docs_urls,
引數title為介面檔案網站的標題,
from rest_framework.documentation import include_docs_urls
urlpatterns = [
...
url(r'^docs/', include_docs_urls(title='My API title'))
]
3. 檔案描述說明的定義位置
1) 單一方法的視圖,可直接使用類視圖的檔案字串,如
class BookListView(generics.ListAPIView):
"""
回傳所有圖書資訊.
"""
2)包含多個方法的視圖,在類視圖的檔案字串中,分開方法定義,如
class BookListCreateView(generics.ListCreateAPIView):
"""
get:
回傳所有圖書資訊.
post:
新建圖書.
"""
3)對于視圖集ViewSet,仍在類視圖的檔案字串中分開定義,但是應使用action名稱區分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
"""
list:
回傳圖書串列資料
retrieve:
回傳圖書詳情資料
latest:
回傳最新的圖書資料
read:
修改圖書的閱讀量
"""
4. 訪問介面檔案網頁
瀏覽器訪問 127.0.0.1:8000/docs/,即可看到自動生成的介面檔案,

兩點說明:
1) 視圖集ViewSet中的retrieve名稱,在介面檔案網站中叫做read
2)引數的Description需要在模型類或序列化器類的欄位中以help_text選項定義,如:
class BookInfo(models.Model):
...
bread = models.IntegerField(default=0, verbose_name='閱讀量', help_text='閱讀量')
...
或
class BookReadSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = ('bread', )
extra_kwargs = {
'bread': {
'required': True,
'help_text': '閱讀量'
}
}
5.10 JWT
1 介紹
用于在前后端分離時,實作用戶登錄相關,
一般用戶認證有2中方式:
-
token
用戶登錄成功之后,生成一個隨機字串,自己保留一分+給前端回傳一份, 以后前端再來發請求時,需要攜帶字串, 后端對字串進行校驗, -
jwt
用戶登錄成功之后,生成一個隨機字串,給前端, - 生成隨機字串 {typ:"jwt","alg":'HS256'} {id:1,username:'alx','exp':10} 98qow39df0lj980945lkdjflo.saueoja8979284sdfsdf.asiuokjd978928374 - 型別資訊通過base64加密 - 資料通過base64加密 - 兩個密文拼接在h256加密+加鹽 - 給前端回傳 98qow39df0lj980945lkdjflo.saueoja8979284sdfsdf.asiuokjd978928375 前端獲取隨機字串之后,保留起來, 以后再來發送請求時,攜帶98qow39df0lj980945lkdjflo.saueoja8979284sdfsdf.asiuokjd978928375, 后端接受到之后, 1.先做時間判斷 2.字串合法性校驗,
2 安裝
pip3 install djangorestframework-jwt
注冊:在settings.py的INSTALLED_APPS中添加'rest_framework',
INSTALLED_APPS = [
'rest_framework_jwt'
]
REST_FRAMEWORK = {
# 全域認證配置
"DEFAULT_AUTHENTICATION_CLASSES": ["api.extensions.auth.HulaQueryParamAuthentication", ],
# "UNAUTHENTICATED_USER": None,
# "UNAUTHENTICATED_TOKEN": None,
}
# token過期時間
import datetime
JWT_AUTH = {
"JWT_EXPIRATION_DELTA": datetime.timedelta(minutes=10)
}
3 案例
-
用戶認證
auth.py import jwt from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from rest_framework_jwt.settings import api_settings from api import models class HulaQueryParamAuthentication(BaseAuthentication): def authenticate(self, request): """ # raise Exception(), 不在繼續往下執行,直接回傳給用戶, # return None ,本次認證完成,執行下一個認證 # return ('x',"x"),認證成功,不需要再繼續執行其他認證了,繼續往后權限、節流、視圖函式 """ token = request.query_params.get('token') if not token: raise exceptions.AuthenticationFailed({'code': 10002, 'error': "登錄成功之后才能操作"}) jwt_decode_handler = api_settings.JWT_DECODE_HANDLER try: payload = jwt_decode_handler(token) except jwt.ExpiredSignature: raise exceptions.AuthenticationFailed({'code': 10003, 'error': "token已過期"}) except jwt.DecodeError: raise exceptions.AuthenticationFailed({'code': 10004, 'error': "token格式錯誤"}) except jwt.InvalidTokenError: raise exceptions.AuthenticationFailed({'code': 10005, 'error': "認證失敗"}) jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER username = jwt_get_username_from_payload(payload) user_object = models.UserInfo.objects.filter(username=username).first() return (user_object, token) -
用戶登錄
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework_jwt.settings import api_settings from api import models class LoginView(APIView): """登錄介面""" authentication_classes = [] # 不校驗認證 def post(self, request, *args, **kwargs): """基于Token的認證""" # 1.根據用戶名和密碼檢測用戶是否可以登錄 user = models.UserInfo.objects.filter(username=request.data.get('username'), password=request.data.get('password')).first() if not user: return Response({'code': 10001, 'error': '用戶名或密碼錯誤'}) # 2. 根據user物件生成payload(中間值的資料) jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER payload = jwt_payload_handler(user) # 3. 構造前面資料,base64加密;中間資料base64加密;前兩段拼接然后做hs256加密(加鹽),再做base64加密,生成token jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER token = jwt_encode_handler(payload) return Response({'code': 10000, 'data': token})
5.11 跨域
由于瀏覽器具有“同源策略”的限制,
如果在同一個域下發送ajax請求,瀏覽器的同源策略不會阻止,
如果在不同域下發送ajax,瀏覽器的同源策略會阻止,

- 域相同,永遠不會存在跨域,
- crm,非前后端分離,沒有跨域,
- 路飛學城,前后端分離,沒有跨域(之前有,現在沒有),
- 域不同時,才會存在跨域,
- l拉勾網,前后端分離,存在跨域(設定回應頭解決跨域)
1 解決跨域:CORS
本質在資料回傳值設定回應頭
from django.shortcuts import render,HttpResponse
def json(request):
response = HttpResponse("JSONasdfasdf")
response['Access-Control-Allow-Origin'] = "*"
return response
2 跨域時,發送了2次請求?
在跨域時,發送的請求會分為兩種:
-
簡單請求,發一次請求,
設定回應頭就可以解決 from django.shortcuts import render,HttpResponse def json(request): response = HttpResponse("JSONasdfasdf") response['Access-Control-Allow-Origin'] = "*" return response -
復雜請求,發兩次請求,
- 預檢
- 請求
@csrf_exempt def put_json(request): response = HttpResponse("JSON復雜請求") if request.method == 'OPTIONS': # 處理預檢 response['Access-Control-Allow-Origin'] = "*" response['Access-Control-Allow-Methods'] = "PUT" return response elif request.method == "PUT": return response
條件:
1、請求方式:HEAD、GET、POST
2、請求頭資訊:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 對應的值是以下三個中的任意一個
application/x-www-form-urlencoded
multipart/form-data
text/plain
注意:同時滿足以上兩個條件時,則是簡單請求,否則為復雜請求
3 總結
- 由于瀏覽器具有“同源策略”的限制,所以在瀏覽器上跨域發送Ajax請求時,會被瀏覽器阻止,
- 解決跨域
- 不跨域
- CORS(跨站資源共享,本質是設定回應頭來解決),
- 簡單請求:發送一次請求
- 復雜請求:發送兩次請求
5.12 paramiko
用于幫助開發者通過代碼遠程連接服務器,并對服務器進行操作,
pip3 install paramiko
-
遠程執行命令【用戶名和密碼】
import paramiko # 創建SSH物件 ssh = paramiko.SSHClient() # 允許連接不在know_hosts檔案中的主機 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 連接服務器 ssh.connect(hostname='192.168.16.85', port=22, username='root', password='123456') # 執行命令 stdin, stdout, stderr = ssh.exec_command('df') # 獲取命令結果 result = stdout.read() # 關閉連接 ssh.close() print(result.decode('utf-8')) -
遠程執行命令【公鑰和私鑰】(公鑰必須提前上傳到服務器)
import paramiko private_key = paramiko.RSAKey.from_private_key_file(r'C:/Users/Administrator/.ssh/id_rsa') # 創建SSH物件 ssh = paramiko.SSHClient() # 允許連接不在know_hosts檔案中的主機 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 連接服務器 ssh.connect(hostname='192.168.16.85', port=22, username='root', pkey=private_key) # 執行命令 stdin, stdout, stderr = ssh.exec_command('df') # 獲取命令結果 result = stdout.read() # 關閉連接 ssh.close() print(result) -
遠程上傳和下載檔案【用戶名和密碼】
import paramiko transport = paramiko.Transport(('192.168.16.85', 22)) transport.connect(username='root', password='123456') sftp = paramiko.SFTPClient.from_transport(transport) # 將location.py 上傳至服務器 /tmp/test.py # sftp.put('wy.txt', '/data/wy.txt') sftp.get('/data/wy.txt', 'xx.txt') transport.close() -
遠程上傳和下載檔案【公鑰和私鑰】
import paramiko private_key = paramiko.RSAKey.from_private_key_file(r'C:/Users/Administrator/.ssh/id_rsa') transport = paramiko.Transport(('192.168.16.85', 22)) transport.connect(username='root', pkey=private_key) sftp = paramiko.SFTPClient.from_transport(transport) # 將location.py 上傳至服務器 /tmp/test.py # sftp.put('/tmp/location.py', '/tmp/test.py') # 將remove_path 下載到本地 local_path # sftp.get('remove_path', 'local_path') transport.close()
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/50456.html
標籤:Python
