小入門 Django(做個疫情數據報告)


Django 是 Python web框架,發音 [ˈdʒæŋɡo] ,翻譯成中文叫“姜狗”。

為什么要學框架?其實我們自己完全可以用 Python 代碼從0到1寫一個web網站,但那樣就要寫網絡服務、數據庫讀寫等底層代碼。而框架的作用是把這些底層基建已經搭建好了,我們只寫業務邏輯即可。

舉個例子,樓房就是框架,我們不關心底層的腳手架、鋼筋水泥是如何搭建的,只要有了這樣的框架我們就可以住進去,而里面的房間要怎么設計、裝飾才是我們關心的。

1. 初識Django

我使用的 Python 版本是 3.8,先執行下面語句先安裝 Django

pip install Django

安裝完成后,執行下面語句創建 Django 項目

django-admin startproject duma

項目的名稱可以自定義,我創建的項目名是 duma。

命令執行完畢后,在當前目錄會生成 duma 目錄,該目錄包含以下源文件。

duma/
    manage.py
    duma/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

簡單介紹下這幾個文件的作用:

  • manage.py: 管理 Django 項目的命令行工具,就像一個工具箱,后面會經常用到
  • mysite/settings.py:Django 項目的配置文件,如:配置該項目使用什么數據庫、包含哪些應用等
  • mysite/urls.py:Django 項目的 URL 聲明
  • mysite/asgi.py:作為你的項目的運行在 ASGI 兼容的 Web 服務器上的入口。暫時用不到
  • mysite/wsgi.py:作為你的項目的運行在 WSGI 兼容的Web服務器上的入口。暫時用不到

后面的學習中,我們會使用、修改這上面的文件,那時候對他們的作用會有更深的體會。

運行下面命令,啟動web服務,驗證 duma 項目是否創建成功。

python manage.py runserver

執行命令,會看到有以下信息輸出

Starting development server at http://127.0.0.1:8000/

在瀏覽器訪問 http://127.0.0.1:8000/

img

看到上面的頁面,說明項目創建成功。

image.png

接下來我們要在 duma 項目中創建一個應用(app)。一個項目里可以有多個應用,如電商項目里可以有商城應用、支付應用和會員應用等等。

執行這行命令,創建一個應用

python manage.py startapp ncov

這里創建了一個名為 ncov 的應用,用它來做一個疫情數據報告。項目根目錄會發現有個 ncov 目錄,包含以下文件

ncov/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

先不介紹它們的作用,這些文件后面基本都會用到,到時候會詳細介紹。

2. Hello, World

“Hello, World” 是學習任何編程語言的演示程序,現在我們用 Django 實現一個“Hello, World” web應用。

首先,在 “nocv/views.py” 文件中創建 index 函數

from django.http import HttpResponse


def index(request):
    return HttpResponse('Hello, World!')

然后,在 ncov 目錄中創建 urls.py 文件,它用來定義 ncov 應用包含的 url。如:在電商商城應用中,會有商城首頁 url 和商品詳情的 url。

在 urls.py 文件中添加一個url,使之與 index 函數對應起來。

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

第一個參數是 url 的路徑,這里是空字符串代表 ncov 應用的根路徑;第二個參數是該 url 對應的視圖;第三個參數是該 url 的名稱,可自定義。

最后,在 “duma/urls.py” 添加代碼,將 ncov 應用的 url 注冊到 duma 項目中,添加后的代碼如下

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('ncov/', include('ncov.urls')),

]

在瀏覽器訪問 ncov 應用根路徑 http://127.0.0.1:8000/ncov/

img

如果看到如上圖的頁面就代表成功了。如果啟動的服務關閉了,需要在 duma 目錄執行 python manager.py runserver 命令重新啟動web服務。

img

當訪問 ncov 應用根路徑的時候,瀏覽器會產生一個 http 請求,duma項目的web服務接到該請求后,根據 urls.py 中的配置,調用 “ncov/views.py” 文件的 index 函數來處理該請求,index 函數中用 HttpResponse 將字符串 “Hello, World” 構造為一個 http 響應結果並返回給瀏覽器,瀏覽器接到該響應結果后,在頁面上顯示 “Hello, World” 字符串。

細心的話,你會發現 HttpResponse('Hello, World!') 跟 print('Hello, World') 很像,后者是我們學習 Python 語言時第一個演示程序。它倆都是輸出 “Hello, World” 字符串,前者輸出在瀏覽器上,后者輸出在控制台(命令行)上。

這就是框架的威力,我們只關注業務邏輯,底層的 http 如何請求、如何響應以及如何返回給瀏覽器都是框架幫我們做好了。

3. 連接數據庫

一個電商網站會展現很多商品,這些商品信息都存儲在數據庫中。同樣的,ncov應用也需要把疫情統計數據存儲在數據庫中。

打開 “duma/settings.py” 文件,找到 DATABASES配置,如下

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

這里有一些默認的配置。

“default.ENGINE”代表數據庫引擎是 sqlite3,是一個輕量數據庫。你也可以將數據庫引擎改成 MySQL、MongoDB等。

“default.NAME”是數據庫名稱,對於sqlite數據庫來說這里填數據庫的路徑, BASE_DIR 代表項目根目錄,此時再看下項目根目錄可以發現有 db.sqlite3文件,它是 Django 創建的,后面我們就用它來存儲數據。

不知道你會不會有這樣的疑問,說好的數據庫,怎么是個文件?實際上數據庫的底層就是文件,只不過是在文件之上建立了一套引擎可以將文件中的內容以表格展示,並提供增加、刪除、修改、查找的功能。就好比程序員的本質也是人,只不過從事編程工作所以被稱為程序員。

有了數據庫,還需要在數據庫里創建表。一般來說,可以用數據庫命令直接建表。但由於我們用的是框架,所以就可以用 Django 來操作。

在 “ncov/models.py” 文件中創建一個 Django 模型

from django.db import models


class CyStat(models.Model):
    stat_dt = models.CharField(max_length=10) # 日期
    cy_name = models.CharField(max_length=50) # 國家名稱
    confirm = models.IntegerField() # 累計確診
    dead = models.IntegerField() # 累計死亡
    heal = models.IntegerField() # 累計治愈
    today_confirm = models.IntegerField() # 現有確診
    today_new_confirm = models.IntegerField() # 新增確診

這里定義 CyStat 類用來表示每個國家每天的疫情統計數據。包括 7 個屬性,用 models 中的類對象來初始化。

stat_dt 和 cy_name 定義為 models.CharField類型,代表字符類型。日期是 2021-11-01 這樣的格式,占用10個字符,所以 max_length=10;對國家名稱來說一般不超過 50 個字符,所以它的 max_length=50。

其他幾個字段都是統計數字,用整型即可。

有了數據模型只是第一步,我們要怎么獲取數據呢?這時候就需要將模型與數據庫中的表關聯起來。

首先,將 ncov 應用注冊到 duma 項目里,在 “duma/settings.py” 文件中找到 INSTALLED_APPS 配置,並在數組中添加 ncov 應用,添加后 INSTALLED_APPS 數組如下

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'ncov.apps.NcovConfig'  # 注冊 ncov 應用
]

接着,運行下面命令

python manage.py makemigrations ncov

執行后,可以看到輸出以下信息

Migrations
for 'ncov':
  ncov/migrations/0001_initial.py
    - Create model CyStat

該命令會在 “ncov/migration” 目錄下創建 0001_initial.py 文件,如果看源代碼可能看不出它的功能,我們可以執行下面語句將其轉成 sql 就容易理解了。

python manage.py sqlmigrate ncov 0001

執行后,輸出

BEGIN;
--
-- Create model CyStat
--
CREATE TABLE "ncov_cystat" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "stat_dt" varchar(10) NOT NULL, "cy_name" varchar(50) NOT NULL, "confirm" integer NOT NULL, "dead" integer NOT NULL, "heal" integer NOT NULL, "today_confirm" integer NOT NULL, "today_new_confirm" integer NOT NULL);
COMMIT;

可以發現實際上就是一條建表sql,表名是應用名和模型類名的組合,用下划線連接。除了 id 自動添加外,其他字段名稱和定義與模型類屬性一致。

最后,執行下面命令來完成建表操作

python manage.py migrate

我們可以打開 db.sqlite3 數據庫來查看是否成功。Mac電腦自帶 sqlite3 命令直接打開,Windows 電腦可以安裝 SQLite Administrator客戶端。

在項目根目錄執行,打開數據庫文件

sqlite3 db.sqlite3

執行 .tables 查看數據庫中的表

sqlite> .tables
auth_group django_admin_log
auth_group_permissions django_content_type
auth_permission django_migrations
auth_user django_session
auth_user_groups ncov_cystat
auth_user_user_permissions

可以發現名為 ncov_cystat 的表,它就是按照 CyStat 類創建的表。除此之外還有很多其他表,它們是 Django 框架自帶的,我們可以先忽略。

這樣我們將模型 CyStat 類與數據庫中的 ncov_cystat 表對應的,后續我們需要查詢或者修改數據直接操作 CyStat 類就可以了,而不用寫 sql。

這里我們又可以發現使用 Django 框架的一個優勢 —— 將模型類與數據庫隔離(行話叫解耦)。帶來的好處是,如果未來我們的項目上線后想把 sqlite 數據庫換成 MySQL,我們只需要在 settings.py 文件中修改 DATABASES 的數據庫引擎和數據庫名稱,重新執行建表命令即可。表的定義以及對表的查詢、更新邏輯完全不用改。

img

4. 編寫web頁面

最后一節,我們來編寫web頁面展現數據。有了上面的基礎我們知道,應該在 views.py 文件中查詢 ncov_cystat 表的數據,然后將數據返回給瀏覽器。

首先需要向 ncov_cystat 表中導入一些數據,可以參考之前的文章《用Python繪制全球疫情變化地圖》自己抓取。

我也准備了一部分數據放在 “ncov/sql/插入疫情數據.sql” 源碼包里,復制 1 ~ 60 行 sql 在 sqlite 客戶端執行即可。

sqlite> insert into ncov_cystat(stat_dt, cy_name, confirm, dead, heal, today_confirm, today_new_confirm) VALUES ("2021-09-03", "cn", 123169, 5685, 115024, 2460, 33);
sqlite> insert into ncov_cystat(stat_dt, cy_name, confirm, dead, heal, today_confirm, today_new_confirm) VALUES ("2021-09-04", "cn", 123199, 5685, 115105, 2409, 30);
...

讀取數據,返回給瀏覽器。修改 “ncov/views.py” 文件中的 index 函數

from django.shortcuts import render

from .models import CyStat


def index(request):
    cy_stats = CyStat.objects.filter(cy_name='cn').order_by('-stat_dt')[:7]
    context = {
        'cy_stats': cy_stats
    }

    return render(request, 'ncov/index.html', context)

CyStat.objects 會返回 ncov_cystat 表里所有記錄,filter 用來按照字段過濾表中的數據,'cn'代表中國,cy_name='cn' 表示我們只保留國內數據,order_by 用來按照某字段(列)對返回的結果排序,字段名前加 ‘-’ 代表降序,這里我們只取最近 7 天的數據。

現在我們不能像 “Hello, World” 那樣直接返回,因為那種方式返回的是一個字符串,沒有任何樣式。我們返回的應該是一個 HTML 文件,所以需要調用 reder 函數,返回 “ncov/index.html”。

在 ncov 目錄里創建 “templates/ncov/index.html” 文件,編寫以下代碼

<h3>國內疫情數據</h3>

<table border="1">
    <tr>
        <td>日期</td>
        <td>現有確診</td>
        <td>新增確診</td>
    </tr>
    {% for stat in cy_stats %}
    <tr>
        <td> {{ stat.stat_dt }} </td>
        <td> {{ stat.today_confirm }} </td>
        <td> {{ stat.today_new_confirm }} </td>
    </tr>
    {% endfor %}
</table>

該文件中使用表格來展示數據,你會發現這並不是一個純 HTML 文件。准確來說index.html 是Django 定義的一種模板語言,它支持按照一定的語法寫 Python 代碼,比如說里面的 for 循環、stat對象的使用。

render 函數可以執行解析模板語言,生成純 HTML 文件,返回給瀏覽器。

在瀏覽器訪問 http://127.0.0.1:8000/ncov/ ,可以看到如下頁面

img

雖然數據能展示出來了,但有些丑,需要優化下前端樣式。

img

剛剛說的 HTML 和 Django 模板語言都是標記語言,語法都比較簡單,之前沒學過的朋友可以找些教程簡單補一下。

要展示比較漂亮的圖片,一般要借助 js 實現,有 js 的基礎的朋友可以自己寫前端頁面。如果沒有可以用 pyecharts ,它支持用 Python 代碼制作圖表。

下載 pyecharts GitHub 項目(https://github.com/pyecharts/pyecharts)源碼,將 “pyecharts/render/templates” 目錄中的源文件復制到 “ncov/templates” 目錄中,結果如下

img

繼續修改 index 函數,改為使用 pyecharts API 返回折線圖。

from django.http import HttpResponse
from django.shortcuts import render
from pyecharts.charts import Line, Map
from pyecharts import options as opts

from .models import CyStat


def index(request):
    cy_stat = CyStat.objects.filter(cy_name='cn').order_by('-stat_dt')[:14]

    stat_list = [x.stat_dt for x in cy_stat]
    stat_list.reverse()

    today_confirm_list = [x.today_confirm for x in cy_stat]
    today_confirm_list.reverse()

    today_new_confirm_list = [x.today_new_confirm for x in cy_stat]
    today_new_confirm_list.reverse()

    c = (
        Line()
        .add_xaxis(stat_list)
        .add_yaxis("現有確診", today_confirm_list)
        .add_yaxis("新增確診", today_new_confirm_list)
        .set_global_opts(title_opts=opts.TitleOpts(title="國內疫情數據"))
    )
    return HttpResponse(c.render_embed())

頁面效果如下

img

這樣的效果才像點樣。

img

學到這里,我們已經入門 Django 了,留個作業,看看你能否做出下面的效果。

img

全部代碼(包括作業)關注公眾號 渡碼 回復 “django入門” 獲取。今天介紹的只是 Django 一小部分內容,如果大家反饋較好后面會繼續更新,有問題也可以隨時提問。

duma


免責聲明!

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



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