1.使用PyMySQL連接mysql
在成功連接python內(nèi)嵌的sqlite后,我想嘗試連接這個世界使用人數(shù)最多的數(shù)據(jù)庫-MySQL。于是我去MySQL官網(wǎng)查找官方提供的python驅(qū)動,只找到python3.4版本的,而我自己使用的是python3.5.2,因此無法安裝,百度后發(fā)現(xiàn)有個替代品,即PyMySQL,我在pip中成功得安裝了它并成功得鏈接到我本地的數(shù)據(jù)庫,以下是連接的代碼
#-*- coding=utf-8 -*-
import pymysql
conn=pymysql.connect(host='localhost',port=3306,user='root',password='xxx',db='test',charset='UTF8')
cur=conn.cursor()
cur.execute('insert into user (userid,username) values(1,\'ou\')')
cur.close()
conn.commit()
conn.close()
2.使用SQLAlchemy
在Python中,最有名的ORM框架是SQLAlchemy。我們來看看SQLAlchemy的用法。
首先通過pip安裝SQLAlchemy:
pip install sqlalchemy
然后,利用上次我們在MySQL的test數(shù)據(jù)庫中創(chuàng)建的user表,用SQLAlchemy來試試:
第一步,導入SQLAlchemy,并初始化DBSession:
# 導入:
from sqlalchemy import Column, String, create_enginefrom sqlalchemy.orm
import sessionmakerfrom sqlalchemy.ext.declarative
import declarative_base
# 創(chuàng)建對象的基類:
Base = declarative_base()
# 定義User對象:
class User(Base):
# 表的名字:
__tablename__ = 'user'
# 表的結(jié)構(gòu):
id = Column(String(20), primary_key=True)
name = Column(String(20))
# 初始化數(shù)據(jù)庫連接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 創(chuàng)建DBSession類型:
DBSession = sessionmaker(bind=engine)
以上代碼完成SQLAlchemy的初始化和具體每個表的class定義。如果有多個表,就繼續(xù)定義其他class,例如School:
class School(Base):
__tablename__ = 'school'
id = ...
name = ...
create_engine()用來初始化數(shù)據(jù)庫連接。SQLAlchemy用一個字符串表示連接信息:'數(shù)據(jù)庫類型+數(shù)據(jù)庫驅(qū)動名稱://用戶名:口令@機器地址:端口號/數(shù)據(jù)庫名'
你只需要根據(jù)需要替換掉用戶名、口令等信息即可。
下面,我們看看如何向數(shù)據(jù)庫表中添加一行記錄。
由于有了ORM,我們向數(shù)據(jù)庫表中添加一行記錄,可以視為添加一個User
對象:
# 創(chuàng)建session對象:
session = DBSession()
# 創(chuàng)建新User對象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到數(shù)據(jù)庫:
session.commit()
# 關(guān)閉
session:session.close()
可見,關(guān)鍵是獲取session,然后把對象添加到session,最后提交并關(guān)閉。DBSession對象可視為當前數(shù)據(jù)庫連接。
3.HTTP協(xié)議
協(xié)議是指計算機通信網(wǎng)絡(luò)中兩臺計算機之間進行通信所必須共同遵守的規(guī)定或規(guī)則,超文本傳輸協(xié)議(HTTP)是一種通信協(xié)議,它允許將超文本標記語言(HTML)文檔從Web服務器傳送到客戶端的瀏覽器
目前我們使用的是HTTP/1.1 版本
URL詳解
URL(Uniform Resource Locator) 地址用于描述一個網(wǎng)絡(luò)上的資源, 基本格式如下
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
scheme 指定低層使用的協(xié)議(例如:http, https, ftp)
host HTTP服務器的IP地址或者域名
port# HTTP服務器的默認端口是80,這種情況下端口號可以省略。如果使用了別的端口,必須指明,例如 http://www.cnblogs.com:8080/
path 訪問資源的路徑
url-params
query-string 發(fā)送給http服務器的數(shù)據(jù)
anchor- 錨
HTTP協(xié)議是無狀態(tài)的
http協(xié)議是無狀態(tài)的,同一個客戶端的這次請求和上次請求是沒有對應關(guān)系,對http服務器來說,它并不知道這兩個請求來自同一個客戶端。 為了解決這個問題, Web程序引入了Cookie機制來維護狀態(tài).
HTTP消息的結(jié)構(gòu)
先看Request 消息的結(jié)構(gòu), Request 消息分為3部分,第一部分叫請求行, 第二部分叫http header, 第三部分是body. header和body之間有個空行, 結(jié)構(gòu)如下圖

第一行中的Method表示請求方法,比如"POST","GET", Path-to-resoure表示請求的資源, Http/version-number 表示HTTP協(xié)議的版本號
當使用的是"GET" 方法的時候, body是為空的
Get和Post方法的區(qū)別
Http協(xié)議定義了很多與服務器交互的方法,最基本的有4種,分別是GET,POST,PUT,DELETE. 一個URL地址用于描述一個網(wǎng)絡(luò)上的資源,而HTTP中的GET, POST, PUT, DELETE就對應著對這個資源的查,改,增,刪4個操作。 我們最常見的就是GET和POST了。GET一般用于獲取/查詢資源信息,而POST一般用于更新資源信息.
我們看看GET和POST的區(qū)別
1. GET提交的數(shù)據(jù)會放在URL之后,以?分割URL和傳輸數(shù)據(jù),參數(shù)之間以&相連,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的數(shù)據(jù)放在HTTP包的Body中.
2. GET提交的數(shù)據(jù)大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的數(shù)據(jù)沒有限制.
3. GET方式需要使用Request.QueryString來取得變量的值,而POST方式通過Request.Form來獲取變量的值。
4. GET方式提交數(shù)據(jù),會帶來安全問題,比如一個登錄頁面,通過GET方式提交數(shù)據(jù)時,用戶名和密碼將出現(xiàn)在URL上,如果頁面可以被緩存或者其他人可以訪問這臺機器,就可以從歷史記錄獲得該用戶的賬號和密碼.
狀態(tài)碼
Response 消息中的第一行叫做狀態(tài)行,由HTTP協(xié)議版本號, 狀態(tài)碼, 狀態(tài)消息 三部分組成。
狀態(tài)碼用來告訴HTTP客戶端,HTTP服務器是否產(chǎn)生了預期的Response.
HTTP/1.1中定義了5類狀態(tài)碼, 狀態(tài)碼由三位數(shù)字組成,第一個數(shù)字定義了響應的類別
1XX 提示信息 - 表示請求已被成功接收,繼續(xù)處理
2XX 成功 - 表示請求已被成功接收,理解,接受
3XX 重定向 - 要完成請求必須進行更進一步的處理
4XX 客戶端錯誤 - 請求有語法錯誤或請求無法實現(xiàn)
5XX 服務器端錯誤 - 服務器未能實現(xiàn)合法的請求
看看一些常見的狀態(tài)碼
200 OK
最常見的就是成功響應狀態(tài)碼200了, 這表明該請求被成功地完成,所請求的資源發(fā)送回客戶端
302 Found
重定向,新的URL會在response中的Location中返回,瀏覽器將會使用新的URL發(fā)出新的Request。
304 Not Modified 代表上次的文檔已經(jīng)被緩存了, 還可以繼續(xù)使用
400 Bad Request 客戶端請求與語法錯誤,不能被服務器所理解
403 Forbidden 服務器收到請求,但是拒絕提供服務
404 Not Found 請求資源不存在(輸錯了URL)
500 Internal Server Error 服務器發(fā)生了不可預期的錯誤
503 Server Unavailable 服務器當前不能處理客戶端的請求,一段時間后可能恢復正常
4.WSGI接口
了解了HTTP協(xié)議和HTML文檔,我們其實就明白了一個Web應用的本質(zhì)就是:
瀏覽器發(fā)送一個HTTP請求;
服務器收到請求,生成一個HTML文檔;
服務器把HTML文檔作為HTTP響應的Body發(fā)送給瀏覽器;
瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔并顯示。
所以,最簡單的Web應用就是先把HTML用文件保存好,用一個現(xiàn)成的HTTP服務器軟件,接收用戶請求,從文件中讀取HTML,返回。Apache、Nginx、Lighttpd等這些常見的靜態(tài)服務器就是干這件事情的。
如果要動態(tài)生成HTML,就需要把上述步驟自己來實現(xiàn)。不過,接受HTTP請求、解析HTTP請求、發(fā)送HTTP響應都是苦力活,如果我們自己來寫這些底層代碼,還沒開始寫動態(tài)HTML呢,就得花個把月去讀HTTP規(guī)范。
正確的做法是底層代碼由專門的服務器軟件實現(xiàn),我們用Python專注于生成HTML文檔。因為我們不希望接觸到TCP連接、HTTP原始請求和響應格式,所以,需要一個統(tǒng)一的接口,讓我們專心用Python編寫Web業(yè)務。
這個接口就是WSGI:Web Server Gateway Interface。
WSGI接口定義非常簡單,它只要求Web開發(fā)者實現(xiàn)一個函數(shù),就可以響應HTTP請求。我們來看一個最簡單的Web版本的“Hello, web!”:
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']
上面的application()函數(shù)就是符合WSGI標準的一個HTTP處理函數(shù),它接收兩個參數(shù):
environ:一個包含所有HTTP請求信息的dict
對象;
start_response:一個發(fā)送HTTP響應的函數(shù)。
在application()函數(shù)中,調(diào)用:
start_response('200 OK', [('Content-Type', 'text/html')])
就發(fā)送了HTTP響應的Header,注意Header只能發(fā)送一次,也就是只能調(diào)用一次start_response()函數(shù)。start_response()函數(shù)接收兩個參數(shù),一個是HTTP響應碼,一個是一組list表示的HTTP Header,每個Header用一個包含兩個str的tuple表示。通常情況下,都應該把Content-Type頭發(fā)送給瀏覽器。其他很多常用的HTTP Header也應該發(fā)送。然后,函數(shù)的返回值
b'<h1>Hello, web!</h1>'
將作為HTTP響應的Body發(fā)送給瀏覽器。
有了WSGI,我們關(guān)心的就是如何從environ這個dict對象拿到HTTP請求信息,然后構(gòu)造HTML,通過start_response()發(fā)送Header,最后返回Body。
整個application()函數(shù)本身沒有涉及到任何解析HTTP的部分,也就是說,底層代碼不需要我們自己編寫,我們只負責在更高層次上考慮如何響應請求就可以了。
不過,等等,這個application()函數(shù)怎么調(diào)用?如果我們自己調(diào)用,兩個參數(shù)environ和start_response我們沒法提供,返回的bytes也沒法發(fā)給瀏覽器。所以application()函數(shù)必須由WSGI服務器來調(diào)用。有很多符合WSGI規(guī)范的服務器,我們可以挑選一個來用。但是現(xiàn)在,我們只想盡快測試一下我們編寫的application()函數(shù)真的可以把HTML輸出到瀏覽器,所以,要趕緊找一個最簡單的WSGI服務器,把我們的Web應用程序跑起來。
好消息是Python內(nèi)置了一個WSGI服務器,這個模塊叫wsgiref,它是用純Python編寫的WSGI服務器的參考實現(xiàn)。所謂“參考實現(xiàn)”是指該實現(xiàn)完全符合WSGI標準,但是不考慮任何運行效率,僅供開發(fā)和測試使用。
運行WSGI服務我們先編寫hello.py實現(xiàn)Web應用程序的WSGI處理函數(shù):
# hello.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']
然后,再編寫一個server.py,負責啟動WSGI服務器,加載application()
函數(shù):
# server.py
# 從wsgiref模塊導入:
from wsgiref.simple_server import make_server
# 導入我們自己編寫的application函數(shù):
from hello import application
# 創(chuàng)建一個服務器,IP地址為空,端口是8000,處理函數(shù)是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 開始監(jiān)聽HTTP請求:
httpd.serve_forever()
確保以上兩個文件在同一個目錄下,然后在命令行輸入python server.py
來啟動WSGI服務器:
注意:如果8000端口已被其他程序占用,啟動將失敗,請修改成其他端口。
啟動成功后,打開瀏覽器,輸入http://localhost:8000/,就可以看到結(jié)果了:
如果你覺得這個Web應用太簡單了,可以稍微改造一下,從environ
里讀取PATH_INFO
,這樣可以顯示更加動態(tài)的內(nèi)容:
# hello.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
body = '<h1>Hello, %s!</h1>' % (environ['PATH_INFO'][1:] or 'web')
return [body.encode('utf-8')]
你可以在地址欄輸入用戶名作為URL的一部分,將返回Hello, xxx!