上一章實(shí)現(xiàn)了登錄的部分功能,之所以說(shuō)是部分功能,是因?yàn)橛脩?hù)名和密碼寫(xiě)成固定值肯定是不可以的,一個(gè)整體的功能,至少需要注冊(cè),登錄,密碼修改等,這就需要提供一個(gè)把這些值存儲(chǔ)到數(shù)據(jù)庫(kù)的能力。
當(dāng)前的主流數(shù)據(jù)庫(kù)分為兩種,即關(guān)系數(shù)據(jù)庫(kù)和NoSql數(shù)據(jù)庫(kù),對(duì)于中小型的系統(tǒng)來(lái)說(shuō),兩種數(shù)據(jù)庫(kù)性能,易用性都相當(dāng),都是很好的選擇。
基礎(chǔ)配置
這里使用SQLAlchemy數(shù)據(jù)庫(kù)框架的flask集成包,即flask-SQLAlchemy來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作。
SQLAlchemy是一個(gè)非常好的框架,簡(jiǎn)化了數(shù)據(jù)庫(kù)的操作,即提供了高層次的ORM,也提供了低層次的SQL功能,使用起來(lái)非常方便。
安裝方式與之前類(lèi)型,還是pip命令:
pip3.6 install flask-sqlalchemy
安裝完成之后,對(duì)default的配置部分進(jìn)行修改,首先導(dǎo)入包:
from flask.ext.sqlalchemy import SQLAlchemy
然后配置鏈接字符串:
app.config["SQLALCHEMY_DATABASE_URI"]='mysql://root:1234@localhost/cblog'
配置請(qǐng)求結(jié)束后更改自動(dòng)提交:
app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"]=True
實(shí)例化SQLAlchemy:
db=SQLAlchemy(app)
模型設(shè)置
安裝完成之后,繼續(xù)完善登錄的例子,修改default.py文件,新增User模型(類(lèi))和Role模型(以示關(guān)聯(lián))
Role類(lèi)
class Role(db.Model): #需繼承模型
__tablename__="roles" #db中表明,如果不設(shè)置,則會(huì)與class同的默認(rèn)名
id=db.Column(db.Integer,primary_key=True) #SQLAlchemy要求必須有主鍵,一般命名為id即可
name=db.Column(db.String(50),unique=True) #表示name為字符串,不重復(fù)
users=db.relationship("User",backref='role') #關(guān)聯(lián)user模型,并在user中添加反向引用(backref)
User類(lèi)
class User(db.Model):
__tablename__="users"
id=db.Column(db.Integer,primary_key=True)
username=db.Column(db.String(50),unique=True,index=True) #此列帶索引
password=db.Column(db.String(50))
role_id=db.Column(db.Integer,db.ForeignKey("roles.id")) #外鍵指向roles表中的id列
下面要考慮如何執(zhí)行,要既方便,有不能入侵到邏輯代碼,這就要求不能硬編碼到邏輯代碼中,比如把判斷db狀態(tài)的代碼作為參數(shù)傳遞給app.run(),這時(shí)候shell就派上了用場(chǎng)
配置腳本
想讓flask支持命令行腳本,首先需要安裝flask-script擴(kuò)展:
pip3.6 install flask-script
修改default.py的代碼:
from flask.ext.script import Manager
mamager=Manager(app)
....
if __name__=='__main__':
#app.run(debug=True)
mamager.run()
修改過(guò)之后,再次運(yùn)行:
python default.py
發(fā)現(xiàn)并沒(méi)有成功運(yùn)行,而是有提示:
可以看到,后邊需要參數(shù),分別為shell(執(zhí)行腳本),runserver(啟動(dòng)服務(wù))和幫助
下邊啟動(dòng)服務(wù):
python default.py runserver
服務(wù)成功執(zhí)行
數(shù)據(jù)庫(kù)更多配置
但這個(gè)時(shí)候,訪(fǎng)問(wèn)站點(diǎn)(127.0.0.1:5000),會(huì)出現(xiàn)500錯(cuò)誤,提示沒(méi)有mysql模塊,這是為什么呢?很明顯是沒(méi)有安裝mysql驅(qū)動(dòng)的原因,使用pip命令安裝驅(qū)動(dòng):
pip3.6 install MySQL-python
發(fā)現(xiàn)出現(xiàn)錯(cuò)誤,顯示內(nèi)容為(此處僅為win系統(tǒng)):
根據(jù)提示,安裝c++的工具包,按照提示上的下載地址
http://landinghub.visualstudio.com/visual-cpp-build-tools
下載完成直接為exe文件,安裝
重啟后安裝MySQL-python,發(fā)現(xiàn)還是不可以,經(jīng)百度后才發(fā)現(xiàn),MySQLdb這個(gè)庫(kù)最高只支持到python2.7,不在支持3.x,那只好用其他辦法,使用PyMySQL庫(kù):
pip3.6 install PyMySQL
然后修改default.py的代碼,增加兩行:
import pymysql
pymysql.install_as_MySQLdb()
進(jìn)入源碼,注意這一行:
sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"]
即可成功使用并連接mysql。
瀏覽器輸入連接,正確進(jìn)入站點(diǎn)。
接下來(lái),使用shell建立數(shù)據(jù)庫(kù)表,進(jìn)入default.py根目錄:
python default.py shell
from default import db
db.create_all()
這時(shí)候如果沒(méi)有報(bào)錯(cuò),那么數(shù)據(jù)庫(kù)表應(yīng)該建立完成:
數(shù)據(jù)庫(kù)遷移
那么問(wèn)題來(lái)了,這時(shí)候,對(duì)模型進(jìn)行修改,是不會(huì)反應(yīng)到db中的,那么如果修改怎么辦呢?對(duì)于當(dāng)前來(lái)說(shuō),也很簡(jiǎn)單:
db.drop_all()
db.create_all()
但這個(gè)僅僅是現(xiàn)在調(diào)試時(shí)候使用,如果db中已經(jīng)有了數(shù)據(jù),則這個(gè)肯定是無(wú)法忍受的,這時(shí)候,就輪到數(shù)據(jù)庫(kù)遷移插件Migrate登場(chǎng)了,首先還是一樣,需要進(jìn)行安裝:
pip3.6 install flask-migrate
和之前一樣,安裝完之后修改default.py文件進(jìn)行配置:
from flask.ext.migrate import Migrate,MigrateCommand
migrate=Migrate(app,db) #配置遷移
mamager.add_command("db",MigrateCommand) #配置遷移命令
然后使用init命令初始化遷移倉(cāng)庫(kù)
python default.py db init
命令行顯示:
然后增加migrations目錄:
表示遷移文件已經(jīng)初始化完成。
migrate框架提供了一些命令來(lái)進(jìn)行遷移操作,分別為(使用default.py文件舉例):
#根據(jù)差異創(chuàng)建遷移
python default.py db migrate -m "說(shuō)明"
#改動(dòng)差異
python default.py db upgrade
#取消差異改動(dòng)
python default.py db downgrade
回到表單
接下來(lái)看看登錄如何與數(shù)據(jù)庫(kù)關(guān)聯(lián)起來(lái),修改login方法內(nèi)的代碼:
@app.route("/login",methods=["POST"])
def loginPost():
username=request.form.get("username","")
password=request.form.get("password","")
user=User.query.filter_by(username=username,password=password).first() #數(shù)據(jù)庫(kù)查詢(xún)
if user is not None:
session["user"]=username
return render_template("/index.html",name=username,site_name='myblog')
else:
flash("您輸入的用戶(hù)名或密碼錯(cuò)誤")
return render_template("/login.html") #返回的仍為登錄頁(yè)
執(zhí)行結(jié)果非常完美。
一些總結(jié)
下面是一些關(guān)于python和db相連的總結(jié)性的東西
數(shù)據(jù)類(lèi)型
<table>
<tr><td>db類(lèi)型(SQLAlchemy)</td><td>python類(lèi)型</td></tr>
<tr><td>Integer</td><td>int</td></tr>
<tr><td>SmallInteger</td><td>int</td></tr>
<tr><td>BigInteger</td><td>long</td></tr>
<tr><td>Float</td><td>float</td></tr>
<tr><td>Numeric</td><td>decimal.Decimal</td></tr>
<tr><td>String</td><td>str</td></tr>
<tr><td>Text</td><td>str</td></tr>
<tr><td>Boolean</td><td>bool</td></tr>
<tr><td>Date</td><td>datetime.date</td></tr>
<tr><td>Time</td><td>datetime.time</td></tr>
<tr><td>DateTime</td><td>datetime.datetime</td></tr>
<tr><td>PickleType</td><td>python對(duì)象序列化</td></tr>
<tr><td>LargeBinary</td><td>str(二進(jìn)制)</td></tr>
</table>
列選項(xiàng)
<table>
<tr><td>primary_key</td><td>True為主鍵(每個(gè)對(duì)象至少一列)</td></tr>
<tr><td>unique</td><td>True為不允許重復(fù)</td></tr>
<tr><td>index</td><td>True為創(chuàng)建索引</td></tr>
<tr><td>nullable</td><td>True為可為空,false為不許為空</td></tr>
<tr><td>default</td><td>設(shè)置默認(rèn)值</td></tr>
<tr><td>backref</td><td>為另一模型添加反向引用</td></tr>
<tr><td>primaryjoin</td><td>明確兩個(gè)模型直接的鏈接條件</td></tr>
<tr><td>lazy</td><td>可選值:select:首次訪(fǎng)問(wèn)時(shí)加載,immediate:源對(duì)象加載后立即加載,joined使用聯(lián)結(jié)立即加載,subquery:使用子查詢(xún)立即加載,noload:永不加載,dynamic:不加載記錄,但提供加載的查詢(xún)</td></tr>
<tr><td>uselist</td><td>如果為false,則不使用列表,而使用用標(biāo)量值</td></tr>
<tr><td>order_by</td><td>排序方式</td></tr>
<tr><td>secondary</td><td>多對(duì)多時(shí)指定關(guān)系表的名字</td></tr>
<tr><td>secondaryjoin</td><td>手動(dòng)設(shè)置多對(duì)多關(guān)系中二級(jí)聯(lián)結(jié)條件</td></tr>
</table>
數(shù)據(jù)庫(kù)操作
<table>
<tr><td>db.session.add(model)</td><td>插入或修改記錄(需commit)</td></tr>
<tr><td>db.session.delete(model)</td><td>刪除記錄(需commit)</td></tr>
<tr><td>model.query</td><td>查詢(xún)記錄</td></tr>
</table>
查詢(xún)過(guò)濾器
<table>
<tr><td>all()</td><td>返回全部記錄</td></tr>
<tr><td>filter()</td><td>將過(guò)濾器添加至原查詢(xún),返回新結(jié)果</td></tr>
<tr><td>filter_by()</td><td>將等值過(guò)濾器添加至原查詢(xún),返回新結(jié)果</td></tr>
<tr><td>limit()</td><td>限制結(jié)果數(shù)量,分頁(yè)用</td></tr>
<tr><td>offset()</td><td>偏移結(jié)果,分頁(yè)用</td></tr>
<tr><td>order_by()</td><td>排序</td></tr>
<tr><td>group_by()</td><td>分組</td></tr>
<tr><td>first()</td><td>返回首結(jié)果,沒(méi)有則返回None</td></tr>
<tr><td>first_or_404()</td><td>返回首結(jié)果,沒(méi)有則返回404響應(yīng)</td></tr>
<tr><td>get()</td><td>返回主鍵對(duì)應(yīng)的記錄,沒(méi)有則返回None</td></tr>
<tr><td>get_or_404()</td><td>返回主鍵對(duì)應(yīng)的記錄,沒(méi)有則返回404響應(yīng)</td></tr>
<tr><td>count()</td><td>返回全部數(shù)量</td></tr>
<tr><td>paginate()</td><td>返回Paginate對(duì)象,它包含指定范圍內(nèi)的結(jié)果<td></tr>
</table>
經(jīng)過(guò)這幾章,登錄功能已經(jīng)基本完成,在下一章中將講解用戶(hù)注冊(cè)的相關(guān)功能。