Django - 兩週從入門到熟練工

初識 Django

以前 Python 後端開發框架中,對 Tornado 和 Flask 接觸比較多,前者適合做爲服務框架,後者因爲輕量經常使用來構建簡單的後臺或服務。python

Django 之於上面兩個 Web 框架,其自身實現了不少工具類庫,顯得更爲笨重,但上手以後,不少功能不須要再本身實現,比較方便。docker

因爲已經集成諸多功能,Django 也更常被用來做爲後臺開發框架。數據庫

最近新接手一個後臺開發任務也是基於 Django 開發,所以本文對最近這兩週的所學作個自我總結。django

Django 幾個模塊用法

在具體講代碼以前,我先講講整個系統的架構。後端

剛接手任務時,數據庫使用 MySQL5.5,對應的 Django 版本爲 2.0(支持MySQL5.5的最高版本)。設計模式

考慮到系統對接了不一樣產品線,一些數據格式存在不肯定性,我將數據庫改成支持 JSON 格式的 MySQL5.7,Django 也對應升級到最新版 2.2。固然,使用其餘數據庫也是能夠的,例如 PostgreSQL 或者 MongoDB,爲了避免影響原來開發人員的操做習慣,我仍是繼續使用 MySQL。api

同時考慮到平臺存在上傳、解析 Excel 文件這種耗時操做,我引入 Celery + RabbitMQ 實現這類操做的異步執行,優化用戶體驗。bash

Django 還有不少功能我暫時未使用到,其自己功能之強大着實減小了我造輪子的代碼量,但因爲初學,也確實花了很大功夫琢磨每一個功能。架構

下面講講這兩週接觸到的 Django 的幾個模塊以及基礎用法,更詳細的功能請查看官方文檔。app

manage.py

在正式講功能模塊以前,必須得先介紹一下 Django 自帶的強大的項目管理工具: django-admin

一般咱們建立一個 Django 項目的過程是這樣:

# 安裝 Django
pip install django
# 建立一個 Django 項目
django-admin startproject myproject
複製代碼

在建立好 Django 項目後,項目根路徑會生成一個 manage.py 文件。該文件實際執行的就是 django-admin 的功能,只不過已經配置好一些系統變量。

例如在項目內建立一個名爲 mysite 的 App ,那麼能夠:

# 建立一個 App
python manage.py startapp mysite
複製代碼

記住這個 mysite ,這是你的應用名而不只僅是文件夾名稱,後面的開發代碼都會準確引用這個名稱。

manage.py 管理工具,能夠方便地實現服務啓動、數據庫遷移等操做,特別是數據庫遷移是我最經常使用也最愛用的功能,後面會提到。

Project 與 App

Django 中,有 Project(項目) 與 App(應用) 的概念,其區別以下:

Project 是整個項目的最高層級,能夠在 Project 中對項目所需的依賴、環境等進行配置;

App 依託於項目,一個項目能夠有多個應用。

通常來講,一個獨立的管理後臺項目配置一個應用便可,將不一樣的用戶、項目、任務等功能都同屬於一個 App。而若是須要開發一個內部管理後臺,集成 2 個不一樣的系統,這兩個系統中各有項目、任務等模塊,那麼咱們就建立 2 個 App,由於這兩個應用中的功能互不相關。

Model

Django 可用 ORM(對象關係映射) 模式操做數據庫,舉個例子:

# 獲取當前用戶的用戶名
operator = request.user
return operator.username
複製代碼

簡單的兩行代碼,底層已經由 Django 實現了鏈接數據庫(鏈接池)、查詢用戶表、返回 username 字段值等功能。

猶記得我在使用 Tornado 寫服務時,須要本身維護一個數據庫單例,關心服務啓動時數據庫實例的初始化順序等等...

使用 ORM 就須要你對每張表建立一個 Model ,內含你對錶字段的定義,例如字段類型、默認值、外鍵約束等。

舉個例子,一個 Task 表的 Model :

models.py

class Task(models.Model):
    status = models.IntegerField(default=0)
    assignee = models.ForeignKey(settings.AUTH_USER_MODEL,
                                 related_name='+',
                                 null=True,
                                 on_delete=models.SET_NULL)
    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True)
複製代碼

這裏也有要注意的地方:若是不特殊配置,Model 類名會被做爲數據庫表名的一部分,完整爲:<APP_NAME>_<MODEL_NAME>,例如本例爲 mysite_task

Migration

建立數據庫表的 Model 以後,咱們就能夠用 Migrations 功能建立表的初始化腳本,以及真正在數據庫中建表:

# 初始化遷移腳本
python manage.py makemigrations [<APP_NAME>]
# 執行遷移操做,將數據庫腳本在對應的數據庫中執行一遍
python manage.py migrate
複製代碼

Migration的功能強大在於,當你須要更新某個字段(例如將爲某字段設置默認值)時,你能夠直接修改 Model 中的字段配置便可,而後再次執行 makemigrations ,Django 會爲你新建一個數據庫腳本記錄這次更新,你再執行 migrate 便能將這次更新寫入到數據庫中。

不只如此,咱們還能夠新建一個空的 migrations 腳本,編寫數據插入操做。有這個腳本,咱們能夠在系統遷移時都保持一部分測試數據:

from django.db import migrations

# 插入方法
def insert_task(apps, schema_editor):
    Task = apps.get_model('mysite', "Task")
    db_alias = schema_editor.connection.alias
    Task.objects.using(db_alias).bulk_create([
        Task(name='task1'),
    ])

# 回滾方法
def rollback_task(apps, schema_editor):
    Task = apps.get_model('mysite', "Task")
    db_alias = schema_editor.connection.alias
    Task.objects.using(db_alias).filter(name="task1").delete()


class Migration(migrations.Migration):
    dependencies = [
        ('mysite', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(insert_task, rollback_task),
    ]

複製代碼

每次遷移,Django都會存有記錄,可以判斷當前已經執行的操做,待執行的操做,存在風險的操做等。可使用 showmigrations 查看當前各個應用的數據庫遷移腳本執行狀況:

python manage.py showmigrations
複製代碼

View

Django 是 MVT 模式,View 至關於 MVC 設計模式中的 Controller(控制器) 而非 View(視圖)。真正的視圖由 Template(模版)或者靜態資源提供。

既然做爲控制器,那麼 View 的功能就相對清晰了:對接收到的請求數據(Request)作相應處理,並返回處理結果數據(Response)。

View 能夠是類,也能夠是函數+View裝飾器的模式,直接上官方文檔的代碼吧:

基於類的 View:

from django.http import HttpResponse
from django.views.generic import ListView
from books.models import Book

class BookListView(ListView):
    model = Book

    def head(self, *args, **kwargs):
        last_book = self.get_queryset().latest('publication_date')
        response = HttpResponse('')
        # RFC 1123 date format
        response['Last-Modified'] = last_book.publication_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
        return response
複製代碼

基於裝飾器的 View:

from django.views.decorators.http import require_http_methods

@require_http_methods(["GET", "POST"])
def my_view(request):
    # I can assume now that only GET or POST requests make it this far
    # ...
    pass
複製代碼

這部分更多地涉及到業務邏輯,不夠通用所以很少贅述了。

URL

URL 模塊定義了 View 的路由地址:

mysite/urls.py

from django.urls import path
from books.views import BookListView

urlpatterns = [
    path('books/', BookListView.as_view()),
]
複製代碼

能夠配置多層路由,而後在最上層 URL 使用 includes 爲子路由添加 Prefix:

myproject/urls.py

path('api/v1/', include('mysite.urls')),
複製代碼

Test

做爲測試開發工程師,對單元測試模塊仍是須要了解下的(惋惜目前正處於開發前期,測試用例可能須要在項目基本穩定以後再補充了)。

和大部分 Web 框架同樣,Django 的測試模塊也是提供了一個 HTTP Client,使用相似接口測試的模式進行「單元測試」。

我在編寫 Tornado 單元測試基礎框架時候,是將 Tornado 與數據庫的鏈接 Mock 掉,實際並未操做數據庫。但在 Django 中,因爲數據庫的鏈接並不是由我本身實現,也由於使用了 ORM 模式,因此想真正與其餘服務解耦進行單測有些困難,目前就先保持這種測試模式了。

仍是以官方示例代碼爲例吧,編寫一個測試套件類:

import unittest
from django.test import Client

class SimpleTest(unittest.TestCase):
    def setUp(self):
        # Every test needs a client.
        self.client = Client()

    def test_details(self):
        # Issue a GET request.
        response = self.client.get('/customer/details/')

        # Check that the response is 200 OK.
        self.assertEqual(response.status_code, 200)

        # Check that the rendered context contains 5 customers.
        self.assertEqual(len(response.context['customers']), 5)
複製代碼

運行單元測試:

python manage.py test
複製代碼

代碼目錄結構

在我接手該項目時候,大部分的代碼都糅合在一個 Python 文件中,讓我有代碼潔癖的人看着着實難受。

由於我本身也是才接觸 Django,爲了數理目錄結構我也踩了很多坑,包括將各個模塊拆分紅不一樣的應用等騷操做...

我就直接分享我目前正在使用的大體代碼結構吧:

myapp/          # 存放應用具體實現的代碼等
    app_mod1/
        models.py
        views.py
    app_mod2/
        models.py
        views.py
    admin.py
    app.py
    models.py
    views.py
    urls.py
myproject/      # 存放項目配置文件
    settings.py
    urls.py
dockerfiles/    # 存放先後端Dockerfile
docs/           # 存放項目相關的文檔
tests/          # 存放測試套件
manage.py
README.md
複製代碼

總結

在這個項目中,我還引入了 Django-REST-Framework(DRF) 框架的序列化和分頁模塊,Django-MySQL 對 JSON/List 格式數據的支持,以及 Celery 實現異步與定時任務等操做,總體來講兩週時間對 Django 以及擴展模塊的學習算是滿意,不過背後也是我天天下班繼續工做到11點,週末在家查文檔學習的辛苦。

Django 自己功能強大,是一個很是成熟的 Web 開發框架,可是上手有必定難度,須要下功夫好好消化官方文檔閱讀源碼,而且應用在本身的項目中。

後期會繼續分享本項目開發過程當中的一些經驗技巧,歡迎持續關注!可私聊加羣。

參考

www.djangoproject.com/

相關文章
相關標籤/搜索