服務端編程(六)—— Django 工程的安裝與配置 詳解原理 ORM sql urlpattern 數據庫遷移

前言 ´・ᴗ・`

  • 本節默認您已經安裝了
    • Pycharm
    • Django 3.0
    • 建議直接用pycharm安裝django 實在不行採用pip
    • 本篇測試環境:
      • Pycharm 2020.1
      • django 3.0.2
      • python 3.7
  • 本篇內容將會幫助你學習…
    • 如何建立自己的第一個網站(有着django小火箭2333)
    • django工程目錄的結構 以及相應文件目錄的含義
    • 如何注寫自己的應用
    • 如何進行數據庫遷移
    • ORM 與 原生sql語句的概念
    • url 模式的配置 瞭解path() 轉發重定向
    • 如何運行網站

框架的基本概念

unopinioned vs opinioned
這是個新詞
意思就是 web框架的一種特點

  • opinioned 有主見的
    有種web框架擅長搞定特定的web建站問題 但是除了那些擅長點 其他的方面只有很有限的選擇
  • un-opinioned 沒主見的
    有些web框架 則是所有方面都會讓你自由發展 你都可以自定義 或者說 選擇的範圍很大

scalable
scale 有點"尺寸"相關的概念 意思就是你的web應用 可大可小 適合很方便的調節 而不像傳統的那種 牽一髮而動全身

創建Django工程

我們直接利用pycharm的terminal終端 無需cmd
找到 你想放置django工程的文件夾 比如我選定了django_MDN 文件夾

在這裏插入圖片描述

然後terminal 輸入:

django-admin startproject locallibrary

locallibrary 是項目名稱 你可以隨便改
在這裏插入圖片描述
然後你就會看到這樣的層級目錄:

在這裏插入圖片描述

工程文件解釋

  • init.py 只是說明這玩意是個python package(包)
  • settings.py 包含所有網站的設定 即
    • 註冊所有的web應用
    • 所有的靜態文件的地址
    • 所有數據庫的配置細節
  • urls.py 定義 一些url參數能夠映射到資源的真實地址 或者 是處理此項請求的對象
    甚至可以用於映射一些web應用
  • wsgi.py 幫助你的web應用與服務器通信的
  • manage.py 創建應用 與db交互 啓動服務器等

創建應用

在manage.py 同級目錄 terminal運行:

python manage.py startapp catalog

如果不行 試試

python3 manage.py startapp catalog
py manage.py startapp catalog
py-3 manage.py startapp catalog

之後就能看到pycharm的目錄顯示:
在這裏插入圖片描述
或者你dir 查看目錄內文件 更可信:
在這裏插入圖片描述

應用目錄文件講解

我們的目錄應該是現在這樣的:

locallibrary/
    manage.py
    locallibrary/
    catalog/
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        __init__.py
        migrations/

大部分文件都是可以顧名思義的

  • views.py 存放view
    • view 你可以理解爲 一些對象可以幫我們通過url 找到我們想要的資源 這些的東西 都在view下面 無論是object 繼承於view 還是函數 —— 作爲view的方法
  • models.py 存放data models
    也就是所謂的ORM —— 我們通過django的model 對數據庫建立模型 然後就像操作對象 對象實例 對象屬性 一樣改變數據庫的表 行 與 列的數據
  • tests.py 存放tests
  • admin.py 管理網站的一些配置(configuration)
    比如你作爲圖書館借閱應用的 admin 你可以在admin 網頁(應該是admin site) 後臺管理書本信息的錄入
    意味着 給你一個空間操作這些數據庫信息 只不過不對用戶開放
  • apps.py web應用的登記(register)
  • migrations folder 當你用python更改數據庫以後 我們需要遷移(migration),意思自動幫你更新數據庫 當然你學過MySQL直接用sql 再事務commit 就是真正更新了
  • init.py 照舊 這玩意就是說明這目錄是個py包 可以被工程的別的部分引用

註冊應用

我們已經創建了一個名爲catalog的應用
現在 我們在setting.py 中進行註冊
找到 INSTALLED APP 這個列表 添加上catalog 如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth', # authentic 驗證
    'django.contrib.contenttypes',
    'django.contrib.sessions', # session 會話
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'catalog'
]

可見django已經幫我們內置了一些應用 比如用戶驗證authentication 會話session 等

添加數據庫信息

還是在setting.py

  • MySQL 我就接着我的MySQL教程 來繼續配置數據庫了 如下:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "django", #數據庫名字
        'USER':'root', # 一般默認就是root
        'PASSWORD':'2333', # 你的密碼 
        'HOST':'localhost', # 我們現在還是本地服務器跑着學習 後面上真的雲服務器
        'PORT':'3306' # 端口號
    }
}

你得在mysql創建一個空數據庫,把名字填在“NAME”裏面

  • 或者你也可以用默認的sqlite 雖然不適合實際的商業應用 但是自己玩玩還是ok的
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

如果是其他數據庫 你可以參考官網
或者google csdn等等

別的setting

  • timezone
    我們設成中國的時間咯:
    TIME_ZONE = ‘Asia/Shanghai’
    TIME_ZONE = ‘Asia/Hong_Kong’
    當然你可以設成別的 請看
    主要是database name那邊
  • SECRET_KEY. 目前我們一個demo不用管 不過到產品環節的時候就要更改了 涉及安全問題
  • DEBUG. 這個就是打印debug的日誌用的 生產環節就設計成False就行了

url.py 配置 (hook up)

我們說過 url.py管得是url參數的映射 具體來說 我們用path()函數 將url的參數對應一個view(視圖)
可以想象一下 我們通過一個url參數 比如\best 去查看NBA MVP的時候 肯定出來的是一個頁面 也就是一個視圖 所以path就是幫我們找到 我們要的網頁

大概有三種用法 後面還會補充更多 這裏只是混個臉熟:)

  • 綁定到函數——view.function
    1. 添加包 from my_app import views
    2. 書寫正則表達式'^home' 匹配網址 path(r’^home’, views.home, name=‘home’)
  • 綁定到對象_class 繼承於 view
    1. 添加包 from other_app.views import Home
    2. 書寫正則表達式'catalog/<id>/' 匹配網址 path(r’‘catalog//’’, Home.as_view(), name=‘home’)
    3. 注意 id 匹配任何在catalog/任何字符/ 裏面的任何字符 也就是可以傳參 然後用來 比如展現到你的前端網頁上
  • 將另一種path連接方式綁定到你想要的連接方式(重新使用)
    1. import: from django.urls import include, path
    2. path(‘blog/’, include(‘blog.urls’))

然後當你的path()太多的時候 我們直接用url pattern —— 一個列表 來裝他們 於是我們也可以這麼添加新的path

from django.urls import include
from django.urls import path

urlpatterns += [
    path('catalog/', include('catalog.urls')),
]

urlpattern 這個列表包含所有path

注意 django已經默認給我們url pattern 加了一項:

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

這個意思就是 使用admin/ 可以訪問所有站點(site)上的url 也就是我們寫在url pattern裏面的一堆path
爲啥要有這句?-- admin是管理者(我們)訪問的 當然應該可以測試所有的url(也是我們寫的url模式)

當url太多該怎麼辦?urlpattern

可以想象 假設你的網站有100個web應用 你應當怎麼管理至少上百個url pattern?
很明顯我們會把一些細小的url匹配模式 放到我們應用裏面去 這就是我們必須在我們的應用catalog裏面
加上一個url.py 文件 內容如下:

from django.urls import path
from catalog import views

urlpatterns = [

]

那麼 當瀏覽器請求的url 到達我們網站(site) 有點類似根目錄 我們site會調用根目錄的url.py
然後根目錄的url.py就應該轉發(或者說重定向redirect)到 應用catalog的URL.py 也就是上面我們寫的那個

問題是 如何寫清楚“轉發” 這個操作

我們在根目錄的url.py 裏面寫上:

urlpatterns = [
    path('admin/', admin.site.urls),                     #1
    path('catalog/', include('catalog.urls')),           #2
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),             #3
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) #4

第二句就是 意思 你訪問我網站的catalog 我就把這個請求轉給catalog.urls 也就給catalog目錄下的url.py處理
第三句很有意思

  • 觀察到 寫url pattern的地方是空的 意思是 所有 url請求
  • 因爲我們只有一個應用 乾脆所有網站的事交給catalog去做
  • 於是我們把所有url 轉發到 ‘/catalog/’ —— 第二句 我們已經定義過了的 url映射套路
  • 所以就是 第二句把訪問catalog的全部踢皮球給 catalog/url.py
  • 然後第三句把皮球踢給第二句catalog/url.py (從未見過如此厚顏無恥之徒)
    第1句不解釋 上面講了

第四句 你或許這麼訪問過 提供vue.js 的官方網站
也就是地址欄輸入網址 得到的是人家的源碼
那麼有沒有想過 我們的服務器也可以這麼提供我們寫的前端代碼呢?比如.html .js .css
這就是返回靜態文件
當然Django倒是默認不支持這麼弄 但是不方便我們debug
於是第四句就是搞定這個的——讓我們的服務器也能返回 前端代碼

總之 最後我們要往根目錄urls.py 寫的代碼是:

from django.contrib import admin
from django import views
from django.urls import include
from django.urls import path
from django.views.generic import RedirectView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
    path('admin/', admin.site.urls),                     #1
    path('catalog/', include('catalog.urls')),           #2
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) #4

遷移數據庫 migration

這 是我們運行網站前的最後一步 :)

你會好奇 我們並沒有進行任何數據庫的編寫 那麼 爲啥還遷移數據庫呢?
事實上 django幫你寫好了一部分數據庫的結構 用於後續管理 (別找了 不在model.py裏面^_^)
我們創建的應用 應用相關信息等等 都會保存在django自動創建的數據庫中

另外 希望你別忘了
Django 使用對象關係映射器(ORM)將Django代碼中的模型定義映射到底層數據庫使用的數據結構。
那麼 純ORM 純原生sql 或者兩者混用都是ok得了 個人項目無所謂 團體項目 這個得溝通好:)

這裏 我們要安裝好 mysql-client 庫 直接用pycharm安裝就行
然後
我們在terminal 與manage.py 同級目錄 逐行運行:

python manage.py makemigrations 
python manage.py migrate

注意理解這個遷移過程:實際上 make migrations 只是通過我們ORM python代碼 (model.py裏面的) 轉換成sql 語句 然後 真正執行操作的是 migrate
有種說法是 這個migrate 只是我們數據庫版本控制(version control)的一個提綱(schema)而已

其他遷移的命令細節 可以看官網

ORM vs sql

如果我不放心他自動生成的那些sql怎麼辦 也就我不信任ORM呢?
我們可以查看他生成的代碼
首先 找到所有的migrations
運行:

python manage.py showmigrations
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
catalog
 (no migrations)
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
sessions
 [X] 0001_initial

我們看到熟悉的auth catalog sessions 意味着這些都是 已經安裝好的app (登記好的)
如果沒有在setting登記 就會出現:
在這裏插入圖片描述
第二步 我們拿到app名稱 還有相應的migrations的名字 就可以這樣運行:

python manage.py sqlmigrate auth 0001

注意 這個migration原名賊長 幸好我們可用代號 0001
然後我們就得到了:

BEGIN;
--
-- Create model Permission
--
CREATE TABLE "auth_permission" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varch
ar(50) NOT NULL, "content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id") D
EFERRABLE INITIALLY DEFERRED, "codename" varchar(100) NOT NULL);
--
-- Create model Group
--
CREATE TABLE "auth_group" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(80
) NOT NULL UNIQUE);
CREATE TABLE "auth_group_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "grou
p_id" integer NOT NULL REFERENCES "auth_group" ("id") DEFERRABLE INITIALLY DEFERRED, "permiss
ion_id" integer NOT NULL REFERENCES "auth_permission" ("id") DEFERRABLE INITIALLY DEFERRED);
--
-- Create model User
--
CREATE TABLE "auth_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar
(128) NOT NULL, "last_login" datetime NOT NULL, "is_superuser" bool NOT NULL, "username" varc
har(30) NOT NULL UNIQUE, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL,
 "email" varchar(75) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joi
ned" datetime NOT NULL);
CREATE TABLE "auth_user_groups" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "user_id" i
nteger NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED, "group_id" integ
er NOT NULL REFERENCES "auth_group" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE TABLE "auth_user_user_permissions" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "
user_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED, "permi
ssion_id" integer NOT NULL REFERENCES "auth_permission" ("id") DEFERRABLE INITIALLY DEFERRED)
;
CREATE UNIQUE INDEX "auth_permission_content_type_id_codename_01ab375a_uniq" ON "auth_permiss
ion" ("content_type_id", "codename");
CREATE INDEX "auth_permission_content_type_id_2f476e4b" ON "auth_permission" ("content_type_i
d");
CREATE UNIQUE INDEX "auth_group_permissions_group_id_permission_id_0cd325b0_uniq" ON "auth_gr
oup_permissions" ("group_id", "permission_id");
CREATE INDEX "auth_group_permissions_group_id_b120cbf9" ON "auth_group_permissions" ("group_i
d");
CREATE INDEX "auth_group_permissions_permission_id_84c5c92e" ON "auth_group_permissions" ("pe
rmission_id");
CREATE UNIQUE INDEX "auth_user_groups_user_id_group_id_94350c0c_uniq" ON "auth_user_groups" (
"user_id", "group_id");
CREATE INDEX "auth_user_groups_user_id_6a12ed8b" ON "auth_user_groups" ("user_id");
CREATE INDEX "auth_user_groups_group_id_97559544" ON "auth_user_groups" ("group_id");
CREATE UNIQUE INDEX "auth_user_user_permissions_user_id_permission_id_14a6b632_uniq" ON "auth
_user_user_permissions" ("user_id", "permission_id");
CREATE INDEX "auth_user_user_permissions_user_id_a95ead1b" ON "auth_user_user_permissions" ("
user_id");
CREATE INDEX "auth_user_user_permissions_permission_id_1fbb5f2c" ON "auth_user_user_permissio
ns" ("permission_id");
COMMIT;

如果不放心 就這麼檢查

另外 除了我們在ugly的mysql客戶端輸入sql
我們也可以在sqlyog輸入 就好像我們之前做的那樣
在這裏插入圖片描述
當然 還可以調用sql在python的語言接口(implementation)
也就是調用pyMysql庫 這是它的官方文檔
這幾乎就是真的寫sql語句了其實 不再是ORM 對象關係映射(Object Relational Mapping)

那 運行網站吧

python3 manage.py runserver

我們就這樣運行網站吧 本地服務器 默認端口8000

你可以輸入網址到地址欄: http://127.0.0.1:8000/
然後你就會拿到:
在這裏插入圖片描述
注意 這並不意味你成功了:)
忘了嗎?我們的url映射把所有的皮球踢給了catalog/url.py然而那玩意現在是空的:)
所以他說 你並沒有做任何 configuration on urls pattern

解決問題 很簡單 我們去配置咯
然後這個問題留給下一節 目前 我很享受看到django的小火箭 抖動的樣子:)
在這裏插入圖片描述

將django火箭改成中文

你可以稍微配置一下:
找到根目錄的setting.py:
在這裏插入圖片描述
把這兩句改成中國:

LANGUAGE_CODE = 'zh-hans'
 
TIME_ZONE = 'Asia/Shanghai'

然後啓動服務器python manage.py runserver
中文版小火箭:
在這裏插入圖片描述

總結 ´◡`

這一節 我們終於弄出來人生中第一個網站 雖然展現的是django送我們的小火箭
當然不用擔心 這是我們的一小步 全棧領域的一大步
在這裏插入圖片描述
當然對於我來說 這篇文章這麼長能夠通過審覈也是不容易

下一節 我們聊聊數據庫的控制ORM

另外,小姐姐祝賀你完成第一個django 的 demo
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章