項目需求和項目效果圖:
提供給用戶一個查詢表單,用戶輸入需要查詢的手機號和日期後,就會得到相應的查詢結果。
用戶查詢表單
查詢結果效果圖
爲什麼要先把項目需求和項目效果圖寫在最開始的位置呢?
原因很簡單,爲了節省讀者不必要的時間!讀者先看到項目需求和項目效果圖後,應該能夠基本瞭解到本文是否能夠對你產生幫助。因爲筆者在寫該項目的時候,在查詢一些資料的時候,也參考了一部分博客,而搜到的博客文章內容真真是良莠不齊。很多情況下,搜索到的標題乍一看,好像是自己需要的,但是內容長篇大論,需要筆者花費時間閱讀之後,才發現這根本不是自己需要的;更有甚者,"掛着羊頭賣狗肉",除了標題,內容亂寫一通,和標題根本無半毛錢關係。(請原諒我吐槽一番)鑑於此,我相信很多的讀者和筆者一樣,在根據關鍵詞搜索博客文章時,內心之中一定有了實現功能後的效果圖或者看到最終項目效果圖後就能夠知道是不是自己需要的,再決定要不要花費時間來閱讀。因此,筆者把項目效果圖放在最前面,讀者來到本文之後,看到效果圖就能知道和內心之中希望實現的效果圖是不是一樣的或者類似可以進行借鑑的,如果是一樣的或可以進行借鑑的,那麼筆者很高興幫助到你;如果不是,讀者也不用花費時間通篇閱讀完博客之後,才發現不是自己需要的文章,也能夠節省一部分的時間。
項目整體說明:
1、線上已有運行了一段時間的數據表,不是對通過Django模型新建數據表,而是對已經存在的數據表進行操作
2、數據表關聯關係複雜,希望通過自定義SQL來查詢展示數據。即:數據表關聯關係不理想,無法滿足一對一關聯、一對多關聯(外鍵)、多對多關聯三種關聯關係之中的任何一種(Django模型只支持這三種關聯關係,而且多對多關係需要使用中間表的形式,如果你不太理解這句話,請先自行百度下,多對多表關係模型是怎樣設計的)
而筆者面臨的需求是:三表關聯查詢,有三個表user、session、message。user表的guest_id和session的guest_id相關聯,session表的talk_id和message表的talk_id相關聯,
而且session表的talk_id和message表的talk_id,可能是一對一關係,也可能是一對多關係,還可能是多對多關係,總之不符合Django模型中的關聯關係,如果強行使用,會發生想象不到的問題,這樣情況下,只能自行編寫自定義查詢的SQL,而不能使用Django的模型對象來進行查詢
3、環境:
Django 2.0.13
Linux Centos 6.5
MySQL 5.6
Python 3.4
uWSGI 2.0.17
nginx 1.10.2
Django與Python版本對應關係(讀者不一定非要和筆者使用的相同版本的環境,但是一定要使用符合對應關係版本的軟件,不然會發生預料不到的狀況)
Django version Python versions
1.8 2.7、3.2、3.3、3.4、3.5
1.9、1.10 2.7、3.4、3.5
1.11 2.7、3.4、3.5、3.6
2.0 3.4、3.5、3.6
2.1 3.5、3.6、3.7
4、需要的知識
前端(瞭解)
Python(掌握)
MySQL(瞭解)
Linux(瞭解)
這裏根據的是此表單項目所需知識所佔比例來計算的,實際上筆者自己還是一名DBA,哈哈
項目目錄:
第一部分:基礎
1.MVC&MTV模式介紹
2.安裝Django
3.創建Django項目
4.項目文件說明
5.Django數據庫連接配置
第二部分:Django前後端交互數據處理
1.實現用戶查詢表單功能
2.實現url請求數據後端處理功能
第三部分:Django+uwsgi+nginx 項目部署
1.WSGI、uwsgi、uWSGI介紹及安裝
2.Django+uWSGI+nginx關係
3.項目部署
第一部分:
如果讀者這部分已經有了足夠的瞭解,那麼可以直接跳過進行第二部分的參考
1.MVC&MTV模式介紹
1.軟件設計規範,將業務處理邏輯、數據查詢處理、界面展示代碼分離
2.MVC對應MTV
Model(模型):是應用程序中用於處理應用程序數據邏輯的部分;通常模型對象負責在數據庫中存取數據;負責處理數據
View(視圖):是應用程序中處理數據顯示的部分(對應html文件);通常視圖是依據模型(Model)數據創建的;負責界面展示
Controller(控制器):是應用程序中處理用戶交互的部分;通常控制器負責從視圖(View)讀取數據,控制用戶輸入,並向模型發送數據;負責業務邏輯
MVC處理框架:
用戶請求(url),通過Controller發送給Model,Model處理完數據通過Controller發送給View,View經過渲染,返回給用戶
MTV處理框架:
Django相較於MVC多了一個url分發器(urls.py),作用是將url請求分發給不同的view處理,view再調用相應的Model和Template
2.安裝Django
[root@backup ~]# /home/python3/bin/pip3 install Django==2.0.13(當然了,網上也有使用Python虛擬環境的)
...
Successfully installed Django pytz
Cleaning up...
3.創建Django項目
[root@backup ~]# cd /home/python3/ (進入到想要創建Django項目的目錄下,執行命令後,沒有任何輸出信息,即爲成功創建Django項目,這裏是:user_form)
[root@backup python3]# ./bin/python3 /home/python3/bin/django-admin.py startproject user_form
4.項目文件說明
[root@backup python3]# tree user_form/
user_form/
├── manage.py Django命令行管理工具
├── static 自行創建,存放css、js等靜態文件
├── templatags 自行創建,存放自定義的模板過濾器
├── templates 自行創建,存放html文件
└── user_form
├── __init__.py 一個空文件,它告訴Python這個目錄應該被看做一個Python包
├── settings.py 項目的配置文件
├── urls.py url分發器
└── wsgi.py 全名:Web Server GateWay Interface,Web服務器網關接口,是Django項目與WSGI兼容的Web服務器入口,在部署Django+uwsgi+nginx時使用
5.Django數據庫連接配置
默認情況下,Django使用的是sqlite數據庫,現在要改爲連接遠程的MySQL數據庫(當然了,也支持其他數據庫)
[root@backup ~]# /home/python3/bin/pip3 install pymysql
1.修改項目目錄下的__init__.py文件
import pymysql #因爲Python3使用的數據庫連接驅動爲pymysql,而__init__是Python的一個構造方法,可以啓到初始化的用途,在導入模塊時自動觸發
pymysql.install_as_MySQLdb()
2.修改項目目錄下的settings.py文件
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'xxx',
'USER':'xxxx',
'PASSWORD':'xxxx',
'HOST':'xxx',
'PORT':'3306',
}
}
第二部分:
1.實現用戶查詢表單功能
1)配置settings.py
第一個需要調整的地方是57行(不同Django版本可能會稍有不同),這是爲了讓Django知道到哪裏去查找我們的html文件
57 'DIRS': [os.path.join(BASE_DIR, 'templates')],
第二個需要調整的地方是28行(不同Django版本可能會稍有不同),這是因爲Django默認只能通過127.0.0.1訪問,加上這個可以讓任意地址訪問Django項目,當然了,測試階段如此,後期我們還會調整
28 ALLOWED_HOSTS = ['*']
2)配置url分發器,用來接收用戶的url請求,還記得嗎?(MTV框架)
cat /home/python3/user_form/user_form/urls.py
from django.contrib import admin
from django.urls import path
from . import search
urlpatterns = [
path('admin/', admin.site.urls),
path('user_search/',search.user_search),
]
紅色部分是我們自行配置的,user_search表示用戶請求的部分,而search.user_search表示search模塊中user_search的處理函數,from . import search 表示和urls.py同一級目錄導入
3)配置用戶請求邏輯處理部分,相當於View
cat /home/python3/user_form/user_form/search.py
#coding: utf-8
from django.http import HttpResponse
from django.shortcuts import render_to_response
def user_search(request):
return render_to_response('user_search.html')
4)配置html模板
cat /home/python3/user_form/templates/user_search.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用戶信息搜索</title>
</head>
<body>
<form action="/search3" method="get"> 這是最爲重要的部分,前面我們只是請求了html,只涉及到前端的部分,但實際情況往往是需要將前端的請求數據傳到後端進行處理後,然後返回的,search3就是後端處理函數
<input type="text" name="q" placeholder="請輸入查詢手機號"><br/>
<input type="text" name="startTime" style="width:300px" placeholder="請輸入查詢日期 如: 20190916"><br/>
<input type="submit" value="用戶聊天記錄查詢" ><br/>
</form>
</body>
</html>
2.實現url請求數據後端處理功能
前面雖然實現了 用戶查詢表單功能 的部分,但是實際上,現在很多的網站都是動態網站,是需要和後端數據庫進行交互的,所以,這部分筆者來實現這部分的需求
1)處理前端html傳輸過來的數據部分
cat /home/python3/user_form/user_form/search.py
#coding: utf-8
from django.http import HttpResponse
from django.shortcuts import render_to_response
import pymysql
#用戶查詢表單提交數據部分
def user_search(request):
return render_to_response('user_search.html')
#將表單數據進行後端處理的部分
def search3(request):
try:
request.encoding = 'utf-8'
if request.GET['q'] is '' or request.GET['startTime'] is '':
return HttpResponse('您是否忘記了輸入查詢手機號或者查詢日期?')
else:
names = request.GET['q'].strip()
startTime = request.GET['startTime'].strip()
db = pymysql.connect(host='xxx', user='xxx', passwd='xxx', db='xxx', charset='utf8')
cursor = db.cursor()
sql = 'SELECT a.guest_name,a.mobile,a.weixin,a.qq,a.email,b.se,b.kw,b.referer,b.land_page,' \
'b.guest_area,b.talk_time,b.talk_page,' \
'c.msg_type,c.msg,c.worker_id,c.worker_name ' \
'FROM userInfo%s a INNER JOIN session%s b ON a.guest_id = b.guest_id ' \
'INNER JOIN message%s c ON b.talk_id = c.talk_id WHERE a.guest_name LIKE "%%%s%%"' % (startTime,startTime,startTime,names)
cursor.execute(sql)
result = cursor.fetchall()
if result:
return render_to_response('form.html', {'raw': result}) result會返回一個二元數組
else:
return HttpResponse('很抱歉,沒有匹配的查詢結果,請您檢查輸入的手機號是否正確!')
except Exception as e:
return HttpResponse(e)
2)渲染從後端返回的處理數據(俗稱:套模板)
cat /home/python3/user_form/templates/form.html
渲染內容較多,筆者只選擇其中重要的部分進行講解
{% load staticfiles %} #引用靜態文件,在後面我會說明它的用途
{% load msg_type %} #引用自定義過濾器,在後面我會說明它的用途
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
xxx
<!-- Bootstrap -->
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}"> #引用靜態文件,settings.py文件中需要配置
xxx
</head>
<body>
xxx
<div>
<div class="form-group">
<label for="exampleInputName2" class="col-sm-2 control-label normal">對話時間</label>
<div class="col-sm-10">
<input type="text" class="form-control" value="{{ raw.0.10|riqi }}" readonly> #{{Python引用變量的模板語法,這裏爲取值第一個元祖下標爲10的元素,並交由日期過濾器處理,還記得raw返回的是一個二維元祖嗎?}}
</div>
</div>
<div>
<label for="exampleInputName2" class="col-sm-2 control-label normal">來源頁面</label>
<div>
<input type="text" value="{{ raw.0.7 }}" readonly>
</div>
xxx
</body>
</html>
以上就是最爲核心的處理部分,筆者在這裏列出一些常見的問題和額外的數據處理(比如過濾器的二次處理),希望對你有所幫助
1.如果你的頁面出現瞭如下的問題,而不是筆者在博客開始時展現的效果圖,那麼,毫無疑問,你的樣式引用失敗了
解決方法也很簡單,請自行在settings.py文件中的末尾位置,配置你的靜態文件所在的目錄(筆者的是static,還記得嗎?)
cat /home/python3/user_form/user_form/settings.py
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
STATIC_URL = '/static/'
2.格式化時間戳的問題。如圖所示,我希望查詢出來的數據直接顯示成 2019-06-20 14:06:27 格式,而不是時間戳的形式,這樣來說,對用戶更加的友好不是。類似這種將查詢返回的數據進行二次處理的函數,被稱爲過濾器。類似這樣的需求還有很多,筆者只講這一個做個示例
首先是過濾器的settings.py的配置,在大概66行的地方,填寫如下配置,必須和你返回渲染模板引用的過濾器名稱相同。如:form.html開頭引用的 {% load msg_type %},還記得吧?
54 TEMPLATES = [
55 {
xxx
66 'libraries':{
67 'msg_type':'templatetags.msg_type',
68 },
其次是自定義Django過濾器,並將其註冊到Django過濾器中,然後就可以在返回渲染模板中使用該過濾器了。如:form.html開頭引用的
{% load msg_type %} 引用自定義過濾器
{{ raw.0.10|riqi }} 使用自定義過濾器
cat /home/python3/user_form/templatetags/msg_type.py
@register.filter
def riqi(shijian):
shijian = int(shijian)
return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(shijian))
第三部分:
1.WSGI、uwsgi、uWSGI介紹及安裝
2.Django+uWSGI+nginx關係
3.項目部署
1.WSGI、uwsgi、uWSGI介紹及安裝
WSGI,全名:Web Server Gateway Interface(Web服務器網關接口)。簡單來說,WSGI相當於一個管道,一邊連着Web服務器(如:nginx),另一邊連着用戶的應用(如:Django)。通過此管道,協議之間可以進行轉換。而uWSGI是一個Web服務器,它實現了uwsgi和wsgi兩種協議。(關於協議內容,有興趣的讀者請自行百度)
這個是筆者從網上找到的比較形象的一張示意圖,以作參考:
安裝uwsgi:
/usr/local/python3/bin/pip3 install uwsgi==2.0.17
2.Django+uWSGI+nginx關係
如上圖所示,Server表示nginx、apache等Web服務器;App表示你的應用(如:筆者的Django項目);通過WSGI可以將應用和Web服務器結合起來,只讓uWSGI處理動態請求,而靜態請求讓nginx處理即可,畢竟nginx非常擅長靜態內容的處理
3.項目部署
創建uwsgi配置文件
pwd
/home/python3/user_form
cat uwsgi.ini
[uwsgi]
socket=127.0.0.1:8088 配置這個,只能和nginx結合使用,而且需要和nginx的配置地址相同,讓nginx反代8088的地址,這也是本文的目的,Django + uWSGI + nginx 項目
#http=192.168.32.3:8088 配置這個,啓動uWSGI服務,可以直接使用 http://192.168.32.3:8088 地址進行訪問,因爲uWSGI本身也是一個Web服務器
chdir=/home/python3/user_form Django項目路徑
wsgi-file=user_form/wsgi.py 顧名思義,wsgi file
processes=4 maximum number of worker processes
threads=2
master=true
pidfile=uwsgi.pid
daemonize=uwsgi.log
vacuum = true clear environment on exit
配置nginx
cat /usr/local/nginx/conf/nginx.conf (每個人的nginx路徑都不一樣,別照搬;而且筆者假設你已經安裝了nginx;綠色的是和uWSGI相關的配置信息)
xxx
error_log /usr/local/nginx/logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log /usr/local/nginx/logs/access.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream django {
server 127.0.0.1:8088; 需要和uwsgi.ini 文件中配置的相同
}
server {
listen 80;
server_name lzb1.com;
root /usr/local/python3/project/user_form; Django項目路徑
location / {
include uwsgi_params; 這裏的uwsgi_params是從 /usr/local/nginx/conf/ 路徑下拷貝到Django項目路徑下的,用途是 用於nginx 和 uwsgi 之間的請求格式的轉換
uwsgi_pass django;
}
location /static {
alias /usr/local/python3/project/user_form/static/; static靜態文件路徑,畢竟靜態文件完全可以經由nginx來處理,而不必經過uWSGI
}
}
}
啓動/關閉uWSGI、nginx
pwd
/home/python3/user_form
/usr/local/python3/bin/uwsgi --ini uwsgi.ini 啓動
/usr/local/python3/bin/uwsgi --stop uwsgi.pid 關閉
/usr/local/nginx/sbin/nginx -t 語法檢查
/usr/local/nginx/sbin/nginx 啓動
/usr/local/nginx/sbin/nginx -s stop 關閉
netstat -ntlp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1425/nginx
tcp 0 0 127.0.0.1:8088 0.0.0.0:* LISTEN 1413/uwsgi
配置Windows hosts文件
192.168.32.3 lzb1.com
訪問:
至此,Django + uWSGI+ nginx 用戶表單查詢項目,從簡單的MVC&MTV模式介紹、Django安裝,到實現用戶查詢表單功能、url請求數據後端處理功能,再到最後的將項目部署到linux,使其成爲一個成型的項目,已經全部完成。
題外:
因爲這是筆者第一次使用Python寫成的可以上線使用的項目,文章中難免可能會有一些理解不到位的地方,請觀看的讀者在下方留言指正!同時,俗語講:"萬事開頭難",對於第一次獨立寫成的項目,除了喜悅感和成就感溢於言表之外;寫項目過程之中的困難和彎路,也着實令人苦惱;寫作本文,一方面記錄筆者自己的成長過程和項目成果,另一方面,也爲那些正在苦惱類似表單項目怎麼寫,或者將來也要寫類似項目的讀者提供一個思路,使其少走一些彎路,希望可以幫到你