python 全棧開發,Day94(Promise,箭頭函數,Django REST framework,生成json數據三種方式,serializers,Postman使用,外部python腳本調用django)


昨日內容回顧

1. 內容回顧
    1. VueX
                    VueX分三部分
    1. state         2. mutations         3. actions
    存放數據       修改數據的唯一方式        異步操作
    
    修改state中數據的步驟:
    1. 頁面上交互 觸發數據的變化
    2. 去后端獲取新的數據(異步操作 ajax請求)
    3. dispatch('獲取新數據')                                       --> 放在actions中
    4. 拿到了新數據了
    5. 去更新state中對應的數據(同步操作 state.noteList=[xx,xx,xx])--> 放在mutations中

添加新筆記
    1. 把新的筆記數據發送到后端
        dispatch('添加新筆記數據')       --> dispatch('重新拉取筆記數據')
             --> commit('大倉庫添加筆記')
View Code

 

舉例:

新建一個項目mysite,修改urls.py,增加路徑

from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('ajax_test/', views.ajax_test),
]
View Code

修改views.py,增加視圖函數

from django.shortcuts import render
from django.http import JsonResponse

# Create your views here.
def index(request):
    return render(request,"index.html")

def ajax_test(request):
    return JsonResponse({"code":0})
View Code

增加index.html,注意:ajax的路徑是故意寫錯的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="b1">點我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    function sendAjax() {  //發送ajax請求
        $.ajax({
                url: '/ajax_123/',
                type: 'get',
                success: function (res) {
                    console.log('成功咯!');
                    console.log(res);
                },
                error:function (err) {
                    console.log('出錯啦!');
                    console.log(err);
                }
            })
    };

    $('#b1').click(function () {
        var ret = sendAjax();  //執行方法
        console.log(ret);
    });
</script>
</body>
</html>
View Code

啟動django項目,訪問首頁,點擊按鈕

發現ret的值為undefined,執行sendAjax方法時,無法知道異步請求的狀態是成功還是失敗

 

修改為正確的url,改為ajax_test

刷新頁面,再次點擊

發現ret的值還是為undefined,為什么呢?因為ajax是異步請求。ret不會等待ajax請求完畢,就直接執行下面一行,所以輸出undefined。

所以說,ajax不能向上面那樣封裝函數!如果不封裝函數,代碼有可能是這樣的

$.ajax({
    url: '/ajax_123/',
    type: 'get',
    success: function (res) {
       $.ajax({
            url: '/ajax_456/',
            type: 'get',
            success: function (res) {
               ...
            },
            error:function (err) {
                ...
            }
        })
    },
    error:function (err) {
        ...
    }
})
View Code

代碼太冗長了,必須要封裝函數。

針對不能獲取值的問題,使用Promise,就可以解決!

 

一、Promise

Promise,他是一個對象,是用來處理異步操作的,可以讓我們寫異步調用的時候寫起來更加優雅,更加美觀便於閱讀。顧名思義為承諾、許諾的意思,意思是使用了Promise之后他肯定會給我們答復,無論成功或者失敗都會給我們一個答復,所以我們就不用擔心他跑了哈哈。所以,Promise有三種狀態:pending(進行中),resolved(完成),rejected(失敗)。只有異步返回的結構可以改變其狀態。所以,promise的過程一般只有兩種:pending->resolved或者pending->rejected。

promise對象還有一個比較常用的then方法,用來執行回調函數,then方法接受兩個參數,第一個是成功的resolved的回調,另一個是失敗rejected的回調,第二個失敗的回調參數可選。並且then方法里也可以返回promise對象,這樣就可以鏈式調用了。接下來上代碼:

 

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="b1">點我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    function sendAjax(arg) {
        return new Promise(function (resolve, reject) {
            $.ajax({
                url: arg,
                type: 'get',
                success: function (res) {
                    console.log("成功咯");
                    resolve(res)
                },
                error:function (err) {
                    console.log("出錯啦");
                    reject(err)
                }
            })
        })
    };

    $('#b1').click(function () {
        //執行方法,指定url為/ajax_test/
        var ret = sendAjax('/ajax_test/');
        ret.then(function (value) {  //成功時,執行
            console.log(value);
        }).catch(function (err) {   //失敗時,執行
            console.log(err)
        });
    })
</script>
</body>
</html>
View Code

上邊代碼中,定義了一個ret變量,然后執行sendAjax函數,函數返回一個Promise對象,然后對象里邊接收一個匿名函數,分別把resolve跟reject方法當參數傳進去,用ajax來模擬異步請求

當執行resolve方法后就會調用then方法的一個函數。結果如下:

這樣的話,就可以指定ajax異步請求的狀態是成功還是失敗。

在小程序應用中,會大量應用到Promise。

如果想往前端方向發展,有一個面試題,手寫一個promise。當然不是上面的代碼,而是寫底層原理!

 

二、箭頭函數

箭頭函數就是個簡寫形式的函數表達式,並且它擁有詞法作用域的this值(即不會新產生自己作用域下的this,arguments,super和new.target等對象)。此外,箭頭函數總是匿名的。

基礎語法

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
         // equivalent to:  => { return expression; }
 
// 如果只有一個參數,圓括號是可選的:
(singleParam) => { statements }
singleParam => { statements }
 
// 無參數的函數需要使用圓括號:
() => { statements }

each() 

each() 方法為每個匹配元素規定要運行的函數。

提示:返回 false 可用於及早停止循環。

語法

$(selector).each(function(index,element))

 

舉例:打印this

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="b1">點我</button><br/>
<hr>
<div>div1</div>
<div>div2</div>
<div>div3</div>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    $('#b1').click(function () {
        console.log(this);  //this指的是button
        $("div").each(function () {  //循環遍歷div
            console.log(this);  //this指的是div
        })
    })
</script>
</body>
</html>
View Code

刷新網頁,點擊按鈕,查看console

注意:這2個this是不一樣的。上面的this是butthon,下面的this是div

 

一般請求下,如果想讓$("div").each(function () {...}這里面的代碼獲取到button按鈕,

需要在上層定義個變量_this=$(this),然后下面調用_this就可以了。

但是這樣做比較麻煩,使用箭頭函數,就可以解決

將匿名函數改成箭頭函數

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="b1">點我</button><br/>
<hr>
<div>div1</div>
<div>div2</div>
<div>div3</div>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    $('#b1').click(function () {
        console.log(this);  //this指的是button
        $("div").each(()=> {  //循環遍歷div
            console.log(this);
        })
    })
</script>
</body>
</html>
View Code

刷新網頁,重新點擊,效果如下:

總結:

想要內層的this和外層的this一樣,使用箭頭函數,就可以實現!將匿名函數換成箭頭函數

FBV

FBV(function base views) 就是在視圖里使用函數處理請求。

看代碼:

views.py

def index(request):
    if request.method == "POST":
        print(request.POST)
        # 修改數據庫
        return JsonResponse("OK")
    return render(request, "index.html")

def index2(request):
    if request.method == "GET":
        return render(request, "index.html")

    print(request.POST)
    # 修改數據庫
    return JsonResponse("OK")
View Code

上面就是FBV的使用。

這2個視圖函數,都是實現同樣的功能!

那么問題來了,哪個更好一點呢?

答案是第一種,為什么呢?在我們的現有的理念里面,只知道GET和POST。所以這2個視圖函數,是沒有任何區別的。

但是如果一旦上線,對於個人用戶,它可以發送其他類型的,比如PUT。那么線上就會報錯!

所以:對於比較重大的操作,比如修改數據庫,使用if單獨判斷請求類型!

那么我們推薦使用第一種方式!

如果想使用第二種方式,則需要使用if分支判斷,這樣更嚴謹一點。

def index2(request):
    if request.method == "GET":
        return render(request, "index.html")
    elif request.method == "POST":
        print(request.POST)
        # 修改數據庫
        return JsonResponse("OK")
View Code

 

CBV

CBV(class base views) 就是在視圖里使用類處理請求。

將上述代碼中的views.py 修改為如下:

from django import views

class index(views.View):
    def get(self,request):
        return render(request, "index.html")

    def post(self,request):
        print(request.POST)
        # 修改數據庫
        return JsonResponse("OK")
View Code

注意事項:
1. CBV定義一定要繼承django.views.View
2. 注冊路由的時候要寫 類名.as_view()
3. 具體原理是:dispatch()方法 中 利用反射 找到 每個請求要執行的方法

更多詳細介紹,請參考鏈接:

https://www.cnblogs.com/xiao987334176/p/9330368.html#autoid-3-4-0

 

三、Django REST framework

django-rest-framework是一個功能強大且靈活的工具包,用於構建Web API。

您可能希望使用REST框架的一些原因:

 

官方網址:

http://www.django-rest-framework.org/

中文文檔:

https://q1mi.github.io/Django-REST-framework-documentation/

 

上面說了那么多的 RESTful API,其實是為了引出django-rest-framework。它就是專門用來寫API接口的!

一般應用是前后端分離的

前端:

APP、PC網站、手機網頁、手機APP、ipad平板

后端:提供API,返回 JSON格式的數據,就能支撐前端的5種業務!

 

Web API

官方定義如下,強調兩個關鍵點,即可以對接各種客戶端(瀏覽器,移動設備),構建http服務的框架。

為什么要用 Web API

Web API最重要的是可以構建面向各種客戶端的服務。另外與WCF REST Service不同在於,Web API利用Http協議的各個方面來表達服務(例如 URI/request response header/caching/versioning/content format),因此就省掉很多配置。

 

安裝Django rest framework

pip install djangorestframework

提示以下信息,表示安裝成功

Installing collected packages: djangorestframework
Successfully installed djangorestframework-3.8.2

 

四、生成json數據三種方式

准備工作

安裝虛擬環境

在公司開發,一般使用虛擬環境,虛擬環境的安裝,請參考鏈接:

https://www.cnblogs.com/xiao987334176/p/9330368.html#autoid-5-3-0

安裝虛擬環境之后,安裝django,指定版本為1.11.11

pip安裝包臨時指定 從國內的清華pip源下載:

pip install django==1.11.11 -i https://pypi.tuna.tsinghua.edu.cn/simple

將虛擬環境的依賴包關系導出到requirements.txt

pip freeze > requirements.txt

注意:約定成熟使用requirements.txt,一些開源的django項目,里面一般使用這個名字!

查看requirements.txt文件,內容如下:

Django==1.11.11
pytz==2018.5

 

如果需要按照 requirements.txt 安裝項目依賴的第三方包,使用命令:

pip install -r requirements.txt

新建一個虛擬環境,測試一下,就可以了!

 

新建項目about_drf

新建項目時,指定虛擬環境,使用django 1.11.11

修改models.py,增加表

from django.db import models

# Create your models here.


# 文章表
class Article(models.Model):
    title = models.CharField(max_length=32)
    # 文章發布時間
    # auto_now每次更新的時候會把當前時間保存
    create_time = models.DateField(auto_now_add=True)
    # auto_now_add 第一次創建的時候把當前時間保存
    update_time = models.DateField(auto_now=True)
    # 文章的類型
    type = models.SmallIntegerField(
        choices=((1, "原創"), (2, "轉載")),
        default=1
    )
    # 來源
    school = models.ForeignKey(to='School', on_delete=models.CASCADE)
    # 標簽
    tag = models.ManyToManyField(to='Tag')


# 文章來源表
class School(models.Model):
    name = models.CharField(max_length=16)


# 文章標簽表
class Tag(models.Model):
    name = models.CharField(max_length=16)
View Code

說明:

SmallIntegerField 
小整數字段,類似於IntegerField,取值范圍依賴於數據庫特性,[-32768 ,32767]的取值范圍對Django所支持的數據庫都是安全的

SmallIntegerField長度是5位,IntegerField長度是10位

 

choices

用於頁面上的選擇框標簽,需要先提供一個二維的二元元組,第一個元素表示存在數據庫內真實的值,第二個表示頁面上顯示的具體內容。在瀏覽器頁面上將顯示第二個元素的值

 

auto_now_add和auto_now,對於一個字段而言,不能同時寫,只能有一個!

on_delete=models.CASCADE 表示級聯刪除。也就是說,有關系的記錄,會一並刪除!

ManyToManyField 表示多對多,它會自動創建關系表

 

使用2個命令,生成表

python manage.py makemigrations
python manage.py migrate

使用navicat打開sqlite3數據庫

 

增加表數據

執行以下sql語句

# 標簽表
INSERT INTO app01_tag ("id", "name") VALUES (1, 'Python');
INSERT INTO app01_tag ("id", "name") VALUES (2, 'Django');
INSERT INTO app01_tag ("id", "name") VALUES (3, 'Vue');

# 校區表
INSERT INTO app01_school ("id", "name") VALUES (1, '北京校區');
INSERT INTO app01_school ("id", "name") VALUES (2, '上海校區');
INSERT INTO app01_school ("id", "name") VALUES (3, '深圳校區');

# 文章表
INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (1, 'Python三年用不上', '2018-07-31', 1, 1, '2018-07-31');
INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (2, '你不可能知道Vue有多簡單!', '2018-07-31', 2, 2, '2018-07-31');
INSERT INTO app01_article ("id", "title", "create_time", "type", "school_id", "update_time") VALUES (3, 'MySQL一點都不難', '2018-07-31', 1, 3, '2018-07-31');

# 文章和標簽關系表
INSERT INTO app01_article_tag ("id", "article_id", "tag_id") VALUES (1, 1, 1);
INSERT INTO app01_article_tag ("id", "article_id", "tag_id") VALUES (2, 1, 2);
View Code

 

json支持7種數據格式

python 原始類型向 json 類型的轉化對照表:

Python JSON
dict object
list, tuple array
str, unicode string
int, long, float number
True true
False false
None null

 

 

 

 

 

 

日期轉化為字符串

在項目根目錄下,創建文件date_trans.py

import datetime

# 獲取當前時間
now = datetime.datetime.now()
print(now, type(now))

#格式化時間,格式為年-月-日
format_time = now.strftime('%Y-%m-%d')
print(format_time, type(format_time))
View Code

執行輸出:

2018-07-31 19:07:47.346727 <class 'datetime.datetime'>
2018-07-31 <class 'str'>

 

可以發現,格式化之后,數據類型為字符串

 

第一個版本:使用json

修改urls.py,增加路徑

from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^article_list/', views.article_list),
]
View Code

修改views.py,增加視圖函數

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
import json

# Create your views here.

def article_list(request):
    # 去數據庫查詢所有的文章數據
    query_set = models.Article.objects.all().values("id", "title", "create_time", "type", "school__name")
    # 序列化成json格式
    # 1. 先把時間對象轉換成字符串格式
    for i in query_set:
        i["create_time"] = i["create_time"].strftime('%Y-%m-%d')

    data = json.dumps(list(query_set), ensure_ascii=False)
    # 返回
    return HttpResponse(data)
View Code

注意:json只支持7種數據類型,ORM查詢出來的結果為QuerySet類型,它是不支持的。

日期對象也是不支持的,需要轉化為字符串。

啟動django項目,訪問url: http://127.0.0.1:8000/article_list/

頁面輸出:

[{"create_time": "2018-07-31", "school__name": "北京校區", "id": 1, "type": 1, "title": "Python三年用不上"}, {"create_time": "2018-07-31", "school__name": "上海校區", "id": 2, "type": 2, "title": "你不可能知道Vue有多簡單!"}, {"create_time": "2018-07-31", "school__name": "深圳校區", "id": 3, "type": 1, "title": "MySQL一點都不難"}]
View Code

每一個時間,都要轉換為字符串,太麻煩了。

 

第二個版本:JsonResponse

JsonResponse 對象:

class JsonResponse(data, encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None,**kwargs)

這個類是HttpRespon的子類,它主要和父類的區別在於:

  • 1.它的默認Content-Type 被設置為: application/json
  • 2.第一個參數,data應該是一個字典類型,當 safe 這個參數被設置為:False ,那data可以填入任何能被轉換為JSON格式的對象,比如list, tuple, set。 默認的safe 參數是 True. 如果你傳入的data數據類型不是字典類型,那么它就會拋出 TypeError的異常
  • 3.json_dumps_params參數是一個字典,它將調用json.dumps()方法並將字典中的參數傳入給該方法。

 

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
import json

# Create your views here.

def article_list(request):
    # 去數據庫查詢所有的文章數據,返回queryset,每一個元素都是字典
    query_set = models.Article.objects.all().values("id", "title", "create_time", "type", "school")
    print(query_set)
    for i in query_set:
        print(i)
        # 學校對象
        school_obj = models.School.objects.filter(id=i['school']).first()
        # 學校id
        id = school_obj.id
        # 學校的名字
        name = school_obj.name
        # 修改字典,key為school的值
        i["school"] = {"id": id, "name": name}

    # 返回json對象,safe=False表示填入任何能被轉換為JSON格式的對象
    return JsonResponse(list(query_set), safe=False)
View Code

刷新網頁,頁面輸出:

[{"title": "Python\u4e09\u5e74\u7528\u4e0d\u4e0a", "type": 1, "create_time": "2018-07-31", "school": {"name": "\u5317\u4eac\u6821\u533a", "id": 1}, "id": 1}, {"title": "\u4f60\u4e0d\u53ef\u80fd\u77e5\u9053Vue\u6709\u591a\u7b80\u5355\uff01", "type": 2, "create_time": "2018-07-31", "school": {"name": "\u4e0a\u6d77\u6821\u533a", "id": 2}, "id": 2}, {"title": "MySQL\u4e00\u70b9\u90fd\u4e0d\u96be", "type": 1, "create_time": "2018-07-31", "school": {"name": "\u6df1\u5733\u6821\u533a", "id": 3}, "id": 3}]
View Code

使用json格式化工具,效果如下:

它將每一個數據類型做了自動轉換。

 

查看JsonResponse源代碼

def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
             json_dumps_params=None, **kwargs):
    if safe and not isinstance(data, dict):
        raise TypeError(
            'In order to allow non-dict objects to be serialized set the '
            'safe parameter to False.'
        )
    if json_dumps_params is None:
        json_dumps_params = {}
    kwargs.setdefault('content_type', 'application/json')
    data = json.dumps(data, cls=encoder, **json_dumps_params)
    super(JsonResponse, self).__init__(content=data, **kwargs)
View Code

看這一行,是它來處理的。注意:cls表示這個類本身

data = json.dumps(data, cls=encoder, **json_dumps_params)

 

從上面的代碼中,可以看出。針對查詢對應的學校信息,使用了for循環。它是一個外鍵字段,

那如果再查詢一個外鍵字段呢?再來一個for循環?代碼太冗長了!

 

第三個版本:serializers

下面會詳細介紹

 

五、serializers

 serializer 允許復雜數據(比如 querysets 和 model 實例)轉換成python數據類型,然后可以更容易的轉換成 json 或 xml 等。同時,serializer也提供了反序列化功能,允許解析數據轉換成復雜數據類型。

中文文檔鏈接:

https://q1mi.github.io/Django-REST-framework-documentation/api-guide/serializers_zh/

 

聲明序列化器

class DBG(serializers.Serializer):  # 聲明序列化器
    id = serializers.IntegerField()
    title = serializers.CharField()
    create_time = serializers.DateField()
    type = serializers.IntegerField()
    school = serializers.CharField(source="school.name")
View Code

注意:source="school.name" 表示school表中的name字段

 

可以使用它來序列化和反序列化與DBG對象相應的數據。

聲明一個序列化器看起來非常像聲明一個form。我們之前學習form組件時,將需要的字段的類型都指定好了!

 

聲明ModelSerializer

通常你會想要與Django模型相對應的序列化類。

ModelSerializer類能夠讓你自動創建一個具有模型中相應字段的Serializer類。

這個ModelSerializer類和常規的Serializer類一樣,不同的是

  • 它根據模型自動生成一組字段。
  • 它自動生成序列化器的驗證器,比如unique_together驗證器。
  • 它默認簡單實現了.create()方法和.update()方法。

 

聲明一個ModelSerializer如下:

class CYM(serializers.ModelSerializer):
    type = serializers.CharField(source='get_type_display')

    class Meta:
        model = models.Article
        fields = "__all__"  # ("id", "title", "type")
        depth = 1  # 官方推薦不超過10層
View Code

默認情況下,所有的模型的字段都將映射到序列化器上相應的字段。

模型中任何關聯字段比如外鍵都將映射到PrimaryKeyRelatedField字段。默認情況下不包括反向關聯,除非像serializer relations文檔中規定的那樣顯示包含。

 

Model.get_FOO_display

查看官方文檔

https://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.get_FOO_display

對於具有選擇集的每個字段,該對象將具有一個get_FOO_display()方法,其中FOO是該字段的名稱。 此方法返回字段的“可讀”值。

 

參數解釋:

source='get_type_display' 表獲取type字段中選擇集的值。

不懂?看一下models.py中的Article表,看這一段

# 文章的類型
    type = models.SmallIntegerField(
        choices=((1, "原創"), (2, "轉載")),
        default=1
    )

ORM是查詢表的數據,那么這個type在真正存儲時,是1或2。

但是我想要得到"原創"和"轉載",怎么辦?那就需要我上面提到的get_type_display。

注意:type的變量名和字段名必須保持一致,那么使用serializers后,結果集中type的值為"原創"和"轉載",而不是1和2

 

model = models.Article  表示Article表

fields = "__all__"   表示所有字段,如果需要指定字段。可以寫成這樣fields = ("id", "title", "type")

depth = 1   表示深度為1層。有外鍵關聯時,才需要設置depth參數

因為Article表和School表,是一對多的關系,它們之間的關系只有一層。假設說:School表和另外一個表(簡稱B表)有關系。Article表通過School表,要去查詢B表的數據,那么層數就是2,以此類推!

 

使用ModelSerializer

def article_list(request):  # 查詢所有
    # 去數據庫查詢所有的文章數據
    query_set = models.Article.objects.all()
    xbg = CYM(query_set, many=True)
    print(xbg.data)
    # 返回
    return JsonResponse(xbg.data, safe=False)
View Code

參數解釋:

many=True  表示能序列化多個對象

什么意思?article表有多條數據,每一條數據,就是一個對象。我們需要查詢表的所有記錄,所以必須指定many=True。返回一條數據時,不需要指定many=True

 

獲取多條數據

views.py完整代碼如下:

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
import json
from rest_framework import serializers

# Create your views here.

class DBG(serializers.Serializer):  # 聲明序列化器
    id = serializers.IntegerField()
    title = serializers.CharField()
    create_time = serializers.DateField()
    type = serializers.IntegerField()
    school = serializers.CharField(source="school.name")


class CYM(serializers.ModelSerializer):  # 聲明ModelSerializer
    #
    type = serializers.CharField(source='get_type_display')

    class Meta:
        model = models.Article
        fields = "__all__"  # ("id", "title", "type")
        depth = 1  # 官方推薦不超過10層


def article_list(request):  # 查詢所有
    # 去數據庫查詢所有的文章數據
    query_set = models.Article.objects.all()
    xbg = CYM(query_set, many=True)
    print(xbg.data)
    # 返回
    return JsonResponse(xbg.data, safe=False)
View Code

刷新頁面,將數據復制一下,使用json格式化工具,效果如下:

可以看到type的值不是數字,而是選擇集中的值,它做了替換。是下面這一行,做了替換

type = serializers.CharField(source='get_type_display')

school的值,也能顯示相關聯的數據。

 

CYM是通用的,可以多條,也可以一條。

注意:多條的時候,需要加參數many=True。而一條,則不用!

 

獲取一條數據

修改urls.py,增加一個路徑

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^article_list/', views.article_list),
    url(r'article_detail/(\d+)', views.article_detail),
]
View Code

修改views.py,增加視圖函數

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
import json
from rest_framework import serializers

# Create your views here.

class DBG(serializers.Serializer):  # 聲明序列化器
    id = serializers.IntegerField()
    title = serializers.CharField()
    create_time = serializers.DateField()
    type = serializers.IntegerField()
    school = serializers.CharField(source="school.name")


class CYM(serializers.ModelSerializer):  # 聲明ModelSerializer
    #
    type = serializers.CharField(source='get_type_display')

    class Meta:
        model = models.Article
        fields = "__all__"  # ("id", "title", "type")
        depth = 1  # 官方推薦不超過10層


def article_list(request):  # 查詢所有
    # 去數據庫查詢所有的文章數據
    query_set = models.Article.objects.all()
    xbg = CYM(query_set, many=True)
    print(xbg.data)
    # 返回
    return JsonResponse(xbg.data, safe=False)


def article_detail(request, id):  # 查詢單條數據
    article_obj = models.Article.objects.filter(id=id).first()
    xcym = CYM(article_obj)
    return JsonResponse(xcym.data)
View Code

注意:使用這一行代碼

from rest_framework import serializers

必須要用pip install djangorestframework  安裝!!!

 

刷新頁面,訪問url:  http://127.0.0.1:8000/article_detail/1

使用格式化工具,效果如下:

總結:

使用ORM對象轉換為json對象時,推薦使用serializers

 

六、Postman使用

Postman一款非常流行的API調試工具。不僅可以調試簡單的css、html、腳本等簡單的網頁基本信息,它還能夠發送任何類型的HTTP 請求 (GET, HEAD, POST, PUT..),附帶任何數量的參數+ headers。對於開發過程中去調試接口,Postman確實足夠的簡單方便,而且功能強大。

官網地址:

www.getpostman.com

使用windows安裝之后,打開主程序,跳過登錄

 

 訪問文章列表 http://127.0.0.1:8000/article_list/

 

訪問文章詳情   http://127.0.0.1:8000/article_detail/1

 總結:

1. 使用Django 的視圖 自己序列化
    1. HttpResponse
    2. JsonResponse
    3. serializers

2. 使用Django REST Framework 框架的序列化工具類
    1. 安裝
        pip install djangorestframework
    2. 導入
        from rest_framework import serializers
    3. 使用
        class ArticleSerializer(serializers.Serializer):
            ...
View Code

 

七、外部python腳本調用django

有些情況下,我們需要使用python腳本來調用django,從而方便使用django提供的一些指令!

調試ORM

在django項目根目錄下創建文件test_orm.py,它和manage.py是同級的

import os

if __name__ == "__main__":
    # 設置django環境
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_drf.settings")
    import django
    django.setup()

    from app01 import models

    obj = models.Article.objects.filter(id=1).values()
    print(obj)
View Code

執行腳本,輸出如下:

<QuerySet [{'title': 'Python三年用不上', 'id': 1, 'school_id': 1, 'type': 1, 'update_time': datetime.date(2018, 7, 31), 'create_time': datetime.date(2018, 7, 31)}]>

 

清理過期session

如果用戶主動退出,session會自動清除,如果沒有退出就一直保留,記錄數越來越大,要定時清理沒用的session。

django中已經提供了這個方法,推薦把它加入到crontab中自動清理過期的session,防止session表記錄過大,影響訪問速度。

python E:\python_script\django框架\day15\about_drf\manage.py clearsessions

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM