第一次訪(fǎng)問(wèn) django 服務(wù)
本小節(jié)會(huì)創(chuàng)建我們的第一個(gè) Django 工程以及第一個(gè)應(yīng)用,接下來(lái)的所有示例將會(huì)在這個(gè)工程基礎(chǔ)上進(jìn)行演示。
1. 創(chuàng)建第一個(gè)Django應(yīng)用程序
在創(chuàng)建第一個(gè) Django 應(yīng)用程序之前,我們需要使用 pyenv 工具創(chuàng)建相應(yīng)的虛擬環(huán)境,操作如下:
新建一個(gè)統(tǒng)一的目錄,用于存放 Django 工程代碼:
[root@server ~]# mkdir django-manual
[root@server ~]# cd django-manual/
進(jìn)入虛擬環(huán)境,然后建立 django-manual 虛擬環(huán)境。一般而言每個(gè) Django 工程會(huì)創(chuàng)建一個(gè)虛擬環(huán)境,這樣避免各個(gè) Python 項(xiàng)目之間發(fā)生包沖突。建立好虛擬環(huán)境之后,激活虛擬環(huán)境。操作如下:
[root@server django-manual]# pyenv versions
system
* 3.8.1 (set by /root/.pyenv/version)
3.8.1/envs/env-3.8.1
env-3.8.1
# 新建django-manual虛擬環(huán)境
[root@server django-manual]# pyenv virtualenv 3.8.1 django-manual
Looking in links: /tmp/tmpllz1yd5e
Requirement already satisfied: setuptools in /root/.pyenv/versions/3.8.1/envs/django-manual/lib/python3.8/site-packages (41.2.0)
Requirement already satisfied: pip in /root/.pyenv/versions/3.8.1/envs/django-manual/lib/python3.8/site-packages (19.2.3)
# 手動(dòng)新建的虛擬環(huán)境
[root@server django-manual]# pyenv activate django-manual
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
(django-manual) [root@server django-manual]#
接下來(lái),我們需要安裝 Django 2.2.11 版本(提示: django 3.0 最近發(fā)布了,但是還處于初步完善階段,所以本次介紹以 Django 2.2.11 版本為準(zhǔn)):
(django-manual) [root@server django-manual]# pip install django==2.2.11 -i https://pypi.tuna.tsinghua.edu.cn/simple
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting django==2.2.11
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/be/76/7ccbcf52366590ca76997ce7860308b257b79962a4e4fada5353f72d7be5/Django-2.2.11-py3-none-any.whl (7.5MB)
|████████████████████████████████| 7.5MB 71kB/s
Requirement already satisfied: sqlparse in /root/.pyenv/versions/3.8.1/envs/django-manual/lib/python3.8/site-packages (from django==2.2.11) (0.3.1)
Requirement already satisfied: pytz in /root/.pyenv/versions/3.8.1/envs/django-manual/lib/python3.8/site-packages (from django==2.2.11) (2019.3)
Installing collected packages: django
Successfully installed django-2.2.11
WARNING: You are using pip version 19.2.3, however version 20.0.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
(django-manual) [root@server django-manual]# python -c "import django; print(django.__version__)"
2.2.11
這樣子,虛擬環(huán)境中就安裝好了 Django 2.2.11。Django 提供 django-admin
命令來(lái)幫助我們創(chuàng)建項(xiàng)目和應(yīng)用,我們只需要使用 django-admin
命令即可快速創(chuàng)建我們的第一個(gè) Django 項(xiàng)目:
(django-manual) [root@server django-manual]# django-admin startproject first_django_app
(django-manual) [root@server django-manual]# (django-manual) [root@server django-manual]# tree .
.
└── first_django_app
├── first_django_app
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
2 directories, 5 files
Tips:盡量在 Linux 平臺(tái)上完成實(shí)驗(yàn),在 Windows 下操作在安裝 mysqlclient 模塊是會(huì)稍微有些工作要做。
Django 項(xiàng)目可以由多個(gè)應(yīng)用(app)組成,每個(gè)應(yīng)用是一個(gè)邏輯上劃分,即將某一個(gè)功能模塊劃歸到這個(gè)應(yīng)用。創(chuàng)建一個(gè)應(yīng)用使用 django-admin starapp
應(yīng)用名即可:
(django-manual) [root@server django-manual]# cd first_django_app/
(django-manual) [root@server first_django_app]# django-admin startapp hello_app
(django-manual) [root@server first_django_app]# tree .
.
├── first_django_app
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── hello_app
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
3 directories, 12 files
可以看到,在使用 django-admin
執(zhí)行創(chuàng)建 hello_app 應(yīng)用后,該命令給我們生成了 hello_app 以及若干代碼文件。為了能讓 Django 項(xiàng)目運(yùn)行起來(lái),我們需要調(diào)整下 settings.py 文件中的配置:
# settings.py 中默認(rèn)使用 sqlite3
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
...
# 現(xiàn)在調(diào)整成 mysql 數(shù)據(jù)庫(kù),讀者需要自行準(zhǔn)備mysql服務(wù)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_manual',
'USER': 'store',
'PASSWORD': 'xxxxxxxxx',
'HOST': '180.76.152.113',
'PORT': '9000',
}
}
有了數(shù)據(jù)庫(kù)支持,還需要在 Django 那邊安裝 mysql 相關(guān)的模塊包。通常安裝的是 mysqlclient 模塊:
# 安裝相應(yīng)的依賴(lài)包
(django-manual) [root@server first_django_app]# yum install mysql-devel -y
(django-manual) [root@server first_django_app]# pip install mysqlclient -i https://pypi.tuna.tsinghua.edu.cn/simple
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting mysqlclient
Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d0/97/7326248ac8d5049968bf4ec708a5d3d4806e412a42e74160d7f266a3e03a/mysqlclient-1.4.6.tar.gz (85kB)
|████████████████████████████████| 92kB 22.2MB/s
Installing collected packages: mysqlclient
Running setup.py install for mysqlclient ... done
Successfully installed mysqlclient-1.4.6
最后一件事情,在啟動(dòng) Django 服務(wù)之前,必須要先創(chuàng)建數(shù)據(jù)庫(kù)。Django 服務(wù)默認(rèn)并不會(huì)幫我們創(chuàng)建好數(shù)據(jù)庫(kù),我們必須手工建好數(shù)據(jù)庫(kù),然后再啟動(dòng) Django 服務(wù):
[root@server ~]# mysql -u store -pxxxxxxxxx -h 180.76.152.113 -P9000
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 37328
Server version: 5.7.26 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]> CREATE DATABASE IF NOT EXISTS django_manual DEFAULT CHARSET utf8;
Query OK, 1 row affected (0.00 sec)
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| alarms |
| dashboard |
| django_manual |
| graph |
| mysql |
| performance_schema |
| sys |
| uic |
+--------------------+
15 rows in set (0.00 sec)
MySQL [(none)]> exit;
Bye
# ---------------------------------------------------------------------------------------
(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 13, 2020 - 07:29:06
Django version 2.2.11, using settings 'first_django_app.settings'
Starting development server at http://0.0.0.0:8888/
Quit the server with CONTROL-C.
在完成上述這些步驟后,基本的工程就搭建起來(lái)了。接下來(lái)我們從外面訪(fǎng)問(wèn)這個(gè)端口結(jié)果如下:
這個(gè)是 Django 在配置中做的一個(gè)白名單機(jī)制,它有一個(gè) ALLOWED_HOSTS 配置參數(shù),它用來(lái)設(shè)置訪(fǎng)問(wèn)服務(wù)的白名單。如果想要允許任何主機(jī)訪(fǎng)問(wèn),直接設(shè)置如下:
(django-manual) [root@server first_django_app]# cat first_django_app/settings.py
...
DEBUG = True
ALLOWED_HOSTS = ['*']
...
另外,默認(rèn) setting.py
中的 DEBUG 參數(shù)為 True。正因?yàn)槿绱耍?qǐng)求報(bào)錯(cuò)才會(huì)有如此詳細(xì)的提示。在正真上線(xiàn)部署時(shí)候,這個(gè)參數(shù)一定要關(guān)閉。如果我設(shè)置如下參數(shù)再次從外部請(qǐng)求該 Django 服務(wù)時(shí),瀏覽器的輸出結(jié)果如下圖所示。可以看到,除了顯示一個(gè)冷冰冰 400 錯(cuò)誤,無(wú)任何提示。這樣屏蔽錯(cuò)誤信息,防止有人從錯(cuò)誤結(jié)果中推斷服務(wù)漏洞,達(dá)到滲透的目的。
(django-manual) [root@server first_django_app]# cat first_django_app/settings.py
...
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']
...
我們重新設(shè)置好 DEBUG 和 ALLOWED_HOSTS 參數(shù)后,再次請(qǐng)求 Django 服務(wù),可以得到 Dajngo 內(nèi)置的歡迎頁(yè)面,提示我們服務(wù)已經(jīng)正常啟動(dòng)和運(yùn)行。
現(xiàn)在,我們寫(xiě)一個(gè)最簡(jiǎn)單的 Hello, World
字符串輸出到頁(yè)面上。改動(dòng) first_django_app/first_django_app/url.py
文件,這個(gè)文件是所有 url 請(qǐng)求路由的入口,所有的映射關(guān)系都會(huì)先通過(guò)這里:
(django-manual) [root@server first_django_app]# pwd
/root/django-manual/first_django_app
(django-manual) [root@server first_django_app]# cat first_django_app/urls.py
"""
注釋性文本,省略
"""
from django.contrib import admin
from django.urls import path
## 新導(dǎo)入模塊
from django.http import HttpResponse
## 視圖函數(shù)
def hello_world(*args, **kwargs):
return HttpResponse("Hello, world.", content_type="text/plain")
urlpatterns = [
path('admin/', admin.site.urls),
####添加的url映射,由上面的hello_world()函數(shù)處理
path('hello/', hello_world),
]
再次啟動(dòng) Django 服務(wù),訪(fǎng)問(wèn) 8888 端口的 /hello/
路徑,可以看到頁(yè)面出現(xiàn) “Hello, world.” 這樣的字符,說(shuō)明我們的第一個(gè) URL 接口完成。
2. Django應(yīng)用線(xiàn)上部署
對(duì)于 Django 應(yīng)用的線(xiàn)上部署,往往有以下兩種方案:
2.1 使用 gunicorn 工具
gunicorn 是一個(gè) Unix 上被廣泛使用的高性能的 Python WSGI UNIX HTTP Server。和大多數(shù)的 Web 框架兼容,并具有實(shí)現(xiàn)簡(jiǎn)單,輕量級(jí),高性能等特點(diǎn)。用它部署 Flask/Django 這樣的 Python Web 項(xiàng)目再合適不過(guò)了。它的安裝和使用都十分方便,安裝直接在虛擬環(huán)境下執(zhí)行: pip install gunicorn -i https://pypi.tuna.tsinghua.edu.cn/simple
,使用有兩種方式:
直接使用:
# 參數(shù)說(shuō)明:
# -b: 啟動(dòng)綁定ip和端口,0.0.0.0 是指運(yùn)行外面的所有機(jī)器訪(fǎng)問(wèn)
# -w: 啟動(dòng) worker 進(jìn)程數(shù)
# --daemon: 后臺(tái)啟動(dòng)
(django-manual) [root@server first_django_app]# gunicorn first_django_app.wsgi -b 0.0.0.0:8888 --daemon -w 4
配置文件使用:
(django-manual) [root@server first_django_app]# cat gunicorn_config.py
# gunicorn_config.py
import logging
import logging.handlers
from logging.handlers import WatchedFileHandler
import os
import multiprocessing
bind = '0.0.0.0:8888'
# backlog: 服務(wù)器中在pending狀態(tài)的最大連接數(shù),即client處于waiting的數(shù)目。超過(guò)這個(gè)數(shù)目, client連接會(huì)得到一個(gè)error
backlog = 512
timeout = 30
workers = multiprocessing.cpu_count() * 2
threads = 2
loglevel = 'info'
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
accesslog = "/var/log/django-manual/gunicorn_access.log"
errorlog = "/var/log/django-manual/gunicorn_error.log"
(django-manual) [root@server first_django_app]# gunicorn first_django_app.wsgi -c gunicorn_config.py --daemon
關(guān)閉進(jìn)程:
# 簡(jiǎn)單粗暴的關(guān)閉方式
(django-manual) [root@server first_django_app]# killall gunicorn
2.2 使用 uwsgi 工具部署和安裝 Django 服務(wù)
安裝 uwsgi : pip install uwsgi -i https://pypi.tuna.tsinghua.edu.cn/simple
。使用 uwsgi 啟動(dòng) Django 服務(wù),同樣有直接使用命令行啟動(dòng)和使用配置文件啟動(dòng)兩種方式:
# 新建uwsgi的pid保存目錄
(django-manual) [root@server first_django_app]# mkdir uwsgi/
(django-manual) [root@server first_django_app]# cat uwsgi.ini
[uwsgi]
# socket = 0.0.0.0:8888
# 使用http協(xié)議訪(fǎng)問(wèn)
http = 0.0.0.0:8888
# 指定執(zhí)行的目錄
chdir = /root/django-manual/first_django_app
# 非常重要,指定執(zhí)行的wsgi.py文件
module = first_django_app.wsgi
master = true
processes = 5
threads = 5
vacuum = true
stats=%(chdir)/uwsgi/uwsgi.status
pidfile=%(chdir)/uwsgi/uwsgi.pid
# 啟動(dòng) django 服務(wù)
(django-manual) [root@server first_django_app]# uwsgi -d --ini uwsgi.ini
[uWSGI] getting INI configuration from uwsgi.ini
(django-manual) [root@server first_django_app]# ps -ef | grep uwsgi
root 10250 1 4 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10282 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10283 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10284 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10285 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10286 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10287 10250 0 19:32 ? 00:00:00 /root/.pyenv/versions/django-manual/bin/uwsgi -d --ini uwsgi.ini
root 10344 4650 0 19:33 pts/3 00:00:00 grep --color=auto uwsgi
# 停止進(jìn)程用--stop,重載用--reload
(django-manual) [root@server first_django_app]# uwsgi --stop uwsgi/uwsgi.pid
(django-manual) [root@server first_django_app]# ps -ef | grep uwsgi
root 10566 4650 0 19:35 pts/3 00:00:00 grep --color=auto uwsgi
Tips:如果在配置文件中使用 socket 監(jiān)聽(tīng)端口,則需要使用 nginx 轉(zhuǎn)發(fā) http 協(xié)議為 uwsgi 協(xié)議 才行在瀏覽器中訪(fǎng)問(wèn)。
3. 小結(jié)
本小節(jié)我們?cè)敿?xì)介紹了如何創(chuàng)建一個(gè)最簡(jiǎn)單的 Django 應(yīng)用程序,然后講解了由 django-admin 工具生成的所有目錄與文件,最后講解了 Django 應(yīng)用在線(xiàn)上的部署過(guò)程。