Django接口開發


Django接口開發

一、前后端分離

  • 傳統開發模式

url -->> 視圖函數(邏輯判斷、調用數據庫、渲染HTML)-->>向瀏覽器返回HTML頁面。
項目后台的商品列表頁面已經使用傳統開發模式實現了

但是呢,有時候我們需要將這些內容在移動端(手機APP)或者的設備上顯示。那怎么辦呢?
我們可以再編寫一套后台邏輯給移動端使用。但是這樣比較麻煩,工作量比較大。有沒有更簡單的方式呢?我們可以使用前后端分離開發模式

二、前后端分離模型

前后端分離模型指的是后端只負責返回數據,不再負責渲染頁面。前端負責渲染數據

接下來就要探討一下返回的數據類型,如果我們返回Python中的字典或者列表,但是前端人員或者移動端人員不一定會Python語法。我們可以返回一種前端人員、后台人員都會的一種數據類型,這樣就可以順利的完成開發了。一般在開發中我們返回JSON或者XML數據類型

三、JSON和XML

  • JSON介紹

    JSON(JavaScript Object Notation) : 是一種輕量級的數據交換格式,JSON數據格式類似於Python中的字典

  • XML介紹

    XML(Extensible Markup Language): 可擴展標記語言,很少企業使用XML進行數據傳輸,了解即可

  • JsonResponse

    form django.http import JsonResponse

    使用JsonResponse對象可以將Python中的字典或者其他數據類型轉換為JSON數據

    # 路由
    urlpatterns += [
        # 查詢所有商品
        path('api/goodses/', api_view.select_all_goods),
        
    # 視圖
    def select_all_goods(request):
        """查詢所有的商品"""
    
       # 查詢所有商品得到的是QuerySet類型的對象
       goods_qs = Goods.objects.all()
       # 轉成列表字典格式
       goods_list = [{"id": goods.id, "name": goods.name} for goods in goods_qs]
        # JsonResponse
       return JsonResponse(goods_list,safe=False,json_dumps_params=					{"ensure_ascii":False})
    
    

    safe=False可以使用列表,默認只轉換字典格式
    son_dumps_params={"ensure_ascii":False}:顯示中文

四、AJAX

  • AJAX介紹

    AJAX(Asynchronous Javascript And XML)翻譯成中文就是“異步JavaScript和XML”。即使用JavaScript語言與服務器進行異步交互,傳輸的數據為XML(當然,傳輸的數據不只是XML)還有JSON數據

    AJAX還有一個最大的特點就是,當服務器響應時,不用刷新整個瀏覽器頁面,而是可以局部刷新,這一特點給用戶的感受是在不知不覺中完成請求和響應過程
    應用場景:注冊時信息校驗(百度首頁注冊)

  • AJAX格式

    使用原生的JavaScript 使用AJAX 比較麻煩,我們采用 jQuery 實現 AJAX 請求。
    1、語法:$.ajax({參數1:值1,參數2,值2})

    • 參數介紹
    參數 描述
    url 發送請求的地址
    type 請求方式("POST" 或 "GET"), 默認為 "GET"。注意:其它 HTTP 請求方法如 PUT 和 DELETE 也可以使用,但僅部分瀏覽器支持
    data 發送到服務器的數據。格式 {key:value,key:value}
    error 請求失敗時調用此函數
    success 請求成功后的回調函數,參數:由服務器返回數據
    dataType 預期服務器返回的數據類型。如果不指定,瀏覽器會智能判斷

可用值:
"xml": 返回 XML 文檔,可用 jQuery 處理。
"html": 返回純文本 HTML 信息;
"script": 返回純文本 JavaScript 代碼。
"json": 返回 JSON 數據 |

  • 案例:

    1、前端需要做什么?

    • 以何種形式展示:web網頁展示
      發送參數
      獲取響應
      局部刷新-修改DOM

    2、后端需要做什么?

    • 獲取商品類型,根據商品類型查詢商品
      get請求
    # 視圖
    def select_all_goods_by_goodstype(request):
        """查看更多,根據商品類型查詢所有商品"""
        # 接收參數
        goodstype_id = request.GET.get("goodstype_id")
        # 查詢數據
        goods_qs = Goods.objects.filter(goodstype_id=goodstype_id)
        # 轉成列表字典格式
        goods_list = [{"id": goods.id, "name": goods.name,"price":goods.price,"picture":goods.picture.name,"unite":goods.unite} for goods in goods_qs]
        # JsonResponse
        return JsonResponse(goods_list,safe=False,json_dumps_params={"ensure_ascii":False})
    
    
    # 前端頁面
    <script>
        // 根據url中的goodstype_id
        var url = window.location.href;
        var goodstype_id = url.split("?")[1].split("=")[1];
        //發送請求
        $.ajax({
            "url": "/api/more/",
            "method": "get",
            "data": {"goodstype_id": goodstype_id},
            "success": function (data) {
                {#console.log(data)#}
                {#console.log(typeof data)#}
                var divs = ""
                //遍歷
                for(var i=0;i<data.length;i++){
                    var goods = data[i]
                    var id = goods["id"]
                    var name = goods["name"]
                    var picture = goods["picture"]
                    var price = goods["price"]
                    var unite = goods["unite"]
                    divs = divs+'<div class="col-xs-12 col-sm-3"><a href="detail.html" class="thumbnail"><img src="/static/ft/images/'+picture+'" class="img-responsive"></a><p class="text-center">'+name+'</p><p class="text-center myps"><span>¥'+price+'</span><span>'+price+'/'+unite+'</span><span><img src="/static/ft/images/carts.png"/></span></p></div>'
                }
                //修改dom,這里比較費勁
                $("#mybody").html(divs)
    
            },
            "error": function () {
                alert("error")
            }
        })
        $.ajax({
            "url": "/api/goodstype/",
            "method": "get",
            "data": {"goodstype_id": goodstype_id},
            "success": function (data) {
                $("#goodstype").html("全部分類 > "+data["name"])
            },
            "error": function () {
                alert("error")
            }
        })
    </script>
                
    

五、前端渲染

我們可以使用JS中的text、innerHtml、append 等方法,但是比較麻煩,我們可以使用Vue框架中的語法

  • Vue介紹

    Vue 是一套用於構建用戶界面的JavaScript框架,前端使用Vue的目的就是把AJAX里面的數據綁定到前端

  • Vue基本語法

    • 下載引入

    • 1、第一個應用

      在Django的模版中使用Vue時,語法沖突,需要增加標簽verbatim處理

      Vue.js的應用可以分為2個重要的組成部分,一個是視圖(也就是HTML代碼)另外一個是腳本

    • 
      
      
      # Vue使用[[]]語法
      "delimiters":["[[","]]"]
      
    • 2、v-bind 常用於綁定屬性

          <a v-bind:href="url">百度</a>
      
    • v-if 指令用於條件性地渲染一塊內容。這塊內容只會在指令的表達式返回 true值的時候被渲染

    <div id="app">
        <div v-if="type === 'A'">
          A
        </div>
        <div v-else-if="type === 'B'">
          B
        </div>
        <div v-else-if="type === 'C'">
          C
        </div>
        <div v-else>
          Not A/B/C
        </div>
    </div>
        
    <script>
    new Vue({
      el: '#app',
      data: {
        type: 'C'
      }
    })
    </script>
    
    • v-for 可以通過一個對象的屬性來迭代數據
    
    <div id="app">
      <ul>
        <li v-for="value in object">
        {{ value }}
        </li>
      </ul>
    </div>
     
    <script>
    new Vue({
      el: '#app',
      data: {
        object: {
          name: '菜鳥教程',
          url: 'http://www.runoob.com',
          slogan: '學的不僅是技術,更是夢想!'
        }
      }
    })
    </script>
    
    • 可以用 v-on 指令監聽 DOM 事件,並在觸發時運行一些 JavaScript 代碼
    <div id="app">
      <button v-on:click="counter += 1">增加 1</button>
      <p>這個按鈕被點擊了 {{ counter }} 次。</p>
    </div>
     
    <script>
    new Vue({
      el: '#app',
      data: {
        counter: 0
      }
    })
    </script>
    
    • Vue異步請求

      <div id="box">
      	<input type="button" @click="get()" value="點我異步獲取數據(Get)">
      </div>
      <script type = "text/javascript">
      window.onload = function(){
      var vm = new Vue({
          el:'#box',
          data:{
              msg:'Hello World!',
          },
          methods:{
              get:function(){
                  //發送get請求
                  this.$http.get('/try/ajax/ajax_info.txt').then(function(res){
                      document.write(res.body);    
                  },function(){
                      console.log('請求失敗處理');
                  });
              }
          }
      });
      }
      </script>
      
    • 案例:商品中 查看更多 功能

      1、導入包

      2、使用Vue,搭建環境

      <script>
          // 根據url中的goodstype_id
          var url = window.location.href;
          var goodstype_id = url.split("?")[1].split("=")[1];
          //創建VUE對象
          new Vue({
              el: "#mybody",
              delimiters: ["[[", "]]"],
              data: {
                  goods_list: [],
              },
              methods: {
                  select_info: function () {
                      this.$http.get("/api/more/?goodstype_id="+goodstype_id).then(function (content) {
                          //console.log(content)
                          //console.log(content.data)
                          this.goods_list = content.data
                      },function (data) {
                          alert("error")
                      })
                  }
              },
              mounted:function () {//相當於js onload表示窗體加載完畢
                  this.select_info()
              }
          })
      </script>
      

      3、使用Vue綁定

      <div class="panel-body" id="mybody">
                          <div class="col-xs-12 col-sm-3" v-for="goods in goods_list">
                              <a href="detail.html" class="thumbnail">
                                  <img v-bind:src="'/static/ft/images/'+[[goods.picture]]" class="img-responsive">
                              </a>
                              <p class="text-center">[[goods.name]]</p>
      
                              <p class="text-center myps"><span>¥[[goods.price]]</span><span>[[goods.price]]/[[goods.unite]]</span><span><img
                                      src="/static/ft/images/carts.png"/></span></p>
                          </div>
                      </div>
      

六、REST

REST(Representational State Transfer的簡稱,中文翻譯為“表現層狀態轉移”)與技術無關,
是一種軟件架構風格、設計風格,而不是標准,只是提供了一組設計原則和約束條件。基於這個風格

設計的軟件可以更簡潔,更有層次,更易於實現緩存等機制

滿足這些約束條件和原則的應用程序或設計就是 RESTful

REST需要遵循如下10條規則:

1、協議
API與用戶的通信協議,總是使用HTTPS協議

2、域名
在域名上進行區分,例如
子域名方式:
www.ujiuye.com 所有人都知道這是訪問網站
api.ujiuye.com(cts.ujiuye.com) 看到這個網站就就知道返回json、xml數據

Url上區分:
www.ujiuye.com/
www.ujiuye.com/api/ (添加一個api 目錄,讓人一看到就知道是一個接口)

3、版本
因為項目存在着版本迭代更新,因此建議在url上添加版本
www.ujiuye.com/api/v1/
http://www.example.com/app/1.0/foo
v1、1.0: 就是代表第一版

4、路徑
網絡上任何東西都是資源,均使用名詞表示(可復數)
通俗來說,URL不應該使用動作來描述。例如,下面是一些不符合統一接口 要求的URI:
GET:/getUser/1、 POST:/createUser、PUT:/updateUser/1 、DELETE:/deleteUser/1
建議使用 /user/1

5、HTTP動詞
對於資源的具體操作類型,由HTTP動詞表示
常用的HTTP動詞有下面四個(括號里是對應的SQL命令)
GET(SELECT):從服務器取出資源(一項或多項)
POST(CREATE):在服務器新建一個資源
PUT(UPDATE):在服務器更新資源(客戶端提供改變后的完整資源)
DELETE(DELETE):從服務器刪除資源

還有三個不常用的HTTP動詞
PATCH(UPDATE):在服務器更新(更新)資源(客戶端提供改變的屬性)
HEAD:獲取資源的元數據
OPTIONS:獲取信息,關於資源的哪些屬性是客戶端可以訪問改變的

下面是一些例子
GET /zoos:列出所有動物園
POST /zoos:新建一個動物園(上傳文件)
GET /zoos/ID:獲取某個指定動物園的信息
PUT /zoos/ID:更新某個指定動物園的信息(提供該動物園的全部信息)
PATCH /zoos/ID:更新某個指定動物園的信息(提供該動物園的部分信息)
DELETE /zoos/ID:刪除某個動物園
GET /zoos/ID/animals:列出某個指定動物園的所有動物
DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物

6、過濾信息
如果記錄數量很多,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果。
下面是一些常見的參數
?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數
?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序
?animal_type_id=1:指定篩選條件

參數的設計允許存在冗余,即允許API路徑和URL參數偶爾有重復 比如:
GET /zoos/ID/animals
GET /animals?zoo_id=ID
二者含義是相同的

7、狀態碼
服務器向用戶返回的狀態碼和提示信息,常見的有以下一些(方括號中是該狀態碼對應的HTTP動詞)。
200 OK - [GET]:服務器成功返回用戶請求的數據
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
202 Accepted - []:表示一個請求已經進入后台排隊(異步任務)
204 NO CONTENT - [DELETE]:用戶刪除數據成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操作
401 Unauthorized - [
]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)
403 Forbidden - [] 表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的。
404 NOT FOUND - [
]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操作,該操作是冪等的
406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)
410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的
422 Unprocesable entity - [POST/PUT/PATCH] 當創建一個對象時,發生一個驗證錯誤
500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功

8、錯誤處理
如果狀態碼是4xx,服務器就應該向用戶返回出錯信息。一般來說,返回的信息中將error作為鍵名,出錯信息作為鍵值即可。
{error: "Invalid API key"}

9、返回結果
針對不同操作,服務器向用戶返回的結果應該符合以下規范。
GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔

10、超媒體
RESTful API最好做到Hypermedia(即返回結果中提供鏈接,連向其他API方法),使得用戶不查文檔,也知道下一步應該做什么

比如,Github的API就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表
{
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}
從上面可以看到,如果想獲取當前用戶的信息,應該去訪問api.github.com/user,然后就得到了下面結果
{
"message": "Requires authentication",
"documentation_url": "https://developer.github.com/v3"
}
上面代碼表示,服務器給出了提示信息,以及文檔的網址

11、其他
服務器返回的數據格式,應該盡量使用JSON,避免使用XML


免責聲明!

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



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