一、個人學期總結
本人在一學期時間內學習並實現基於Python的Flask框架web建設項目,python是一種面向對象的解釋型計算機程序設計語言,由荷蘭人Guido van Rossum於1989年發明,Python是純粹的自由軟件, 源代碼和解釋器CPython遵循 GPL(GNU General Public License)協議。Python語法簡潔清晰,特色之一是強制用空白符(white space)作為語句縮進。下面簡單分享一下我個人學習python語言后的一些心得和經驗。
一開始接觸python我們學的是簡單的輸出輸入交互和一些數字的計算,有點類似JAVA,但在語法上還是有些區別,python語言優點在於它的簡潔靈活,所以很多時候它都用到符號代替,接着我們import turtle庫,並繪制出多種多樣的圖形,學習了字符串基本操作,凱撒密碼,自制九九乘法表,中英文詞頻統計等等,雖然語句都挺簡單,但這激發了我們對學習python的興趣,並提升了我們對編程語言的思維能力,有助於下半學期我們構建Flask框架制作網頁的學習。
在學習Python+Flask+MysqL的web建設時,我們安裝了mySQL,pycharm和一些python的第三方庫,首先,老師教了我們網頁前端的制作,應用超文本標記語言HTML,初學html,第一次知道五花八門的網頁原來是由許許多多的標簽對組成的,雖然感覺學起來並不難,但是卻很繁瑣,例如每一個網頁的標簽對有很多個,每一個都有它特定的一些功能,包含了標簽對里的眾多參數,要想實現這些標簽對的功能就必須遵循它的書寫規則,一旦有某個字母拼寫錯誤就會報錯,在html里會用顏色的不同來報錯,這種情況還較好處理,但在JS代碼中是不會提示你哪里出錯,所以在編寫過程中要多加細心謹慎。代碼簡單易學是好事,但要做出漂亮好看的前端也是需要有一定的基礎和積累的。雖然繁瑣但卻又很有趣,剛開始接觸html+css+js的時候會想各種辦法去把網頁做好看,嘗試了各種各樣的樣式和標簽對,或者從網頁上cope別人做好的樣式代碼去修改,碰到不會的代碼就問百度解答或同學探討,在這過程中又學會了許多課堂上沒有教過的知識,最終做出的頁面雖然不盡人意,但對初學html的本菜鳥來說也算勉勉強強及格了。
在頁面前端我們做了導骯頁面、登陸注冊頁面、發布頁面以及各自的css和js,在做這些頁面過程中經常碰到一些問題,例如頁面的排版分布,div中文本的居中問題,解決的辦法很簡單,只需要設置好對應div的class,但一開始都會用一些蠢辦法,用空格代替或者用 去填充,雖說不是最佳的解決方法,但也達到了同樣的效果,在后端建設過程中我們引入了flask庫中的Flask, render_template,用於創建一個Flask對象以及頁面的跳轉,引入flask_sqlalchemy庫進行數據庫的關聯映射等,在引入這些庫時沒有太大問題,基本上屬於復制粘貼或照代碼打,但要注意python如果沒有這些庫的話要去命令行先安裝,在后端設計過程我們學了對數據的增刪改查等操作,利用對數據庫的查詢添加功能實現了頁面的登陸、注冊以及發布功能,這些功能的實現根據前端頁面的name屬性名,后台請求接收同名name的值,再將接收的值做一系列增刪查改操作。在對這些name屬性命名時要注意前后端對應且同一頁面不能出現相同名,否則會出現數據傳遞出錯,在做頁面繼承中我就因為忽視了導航頁和登陸注冊頁的同名name屬性,導致了做好的js代碼因接收了錯的數據而失效,在context_processor上下文處理器中也要注意這個問題,因為上下文處理器帶的模型數據可以在所有頁面模板中使用,因此要防止跟各自頁面的請求模型數據同名,一旦重名,數據就會帶錯,頁面上雖然不會報錯,但卻會顯示錯誤的數據給用戶,所以在編程過程中要時刻注意代碼的簡潔清晰和條理性,盡量用更少更優化的代碼實現功能。
在做發布詳情中我們在頁面跳轉請求時帶上需要用到的‘id’,利用該‘id’去后台查詢數據,在做用戶詳情時我們用三個頁面跳轉同一個請求,不同的是在請求中用if語句判斷,判斷各自實現的功能並跳轉不同頁面,同樣在做這些功能時要注意代碼的簡潔,能分開表示的代碼盡量不要擠在一起,注意代碼的規范和格式。不同功能的實現有不同的方法,同一功能的實現也可能有多種方法,多思考用不同的方法實現會幫助我們開拓編程思維,不一定要照着老師的做法墨守成規,同樣,當有不同的方法實現功能時我們要盡量嘗試,並進行比較選出比較優質的代碼進行替換。在編寫代碼時我們也要養成一個好的習慣,多用“Ctrl+Alt+L”進行格式化以便我們清晰的去觀察和修改,明確目標和功能,理解清晰原理和思路再着手編寫,在寫好某個功能的代碼后先按原理檢查是否出錯, 再運行頁面驗證功能,出錯時不要驚慌,先用F12打開頁面控制台查看數據發送、接收情況和紅色報錯項目,或者到pycharm后台里找相應的報錯字眼、提示等等。養成良好的習慣還在於多用“Ctrl+/”打注釋,把個人的理解和思路整理成簡單的注釋,不僅方便自己復習和修改還有利於使用者及他人查看學習。
總之,編程是一門藝術活,像做建築一般,字母是它的鋼筋水泥和磚塊,只有實打實的基礎,地基牢固,才能成就崛起的名勝古跡。其實編程也像做數學題,一道數學題目可能有多種解法,但我們不必要像解數學題那樣講得很詳細,只要一目了然並能清晰簡潔的表達和實現功能即可,只有多去練習多去運用它,少用復制粘貼、投機取巧,我們才能在編程道路上越走越遠。
2017-12-2817:24:19
二、Python+Flask+MysqL的web建設技術過程總結
本人在一學期時間實現了Python+Flask+MysqL的web建設,頁面具有簡單的登錄注冊發布文章搜索文章等功能。
在這里總結分享了我最近一段時間的學習成果:使用Flask框架搭建一個web service,並在其中加上一些簡單的css,js,html等。由於本人是新手,如有錯漏請見諒並歡迎大家批評指出。O(∩_∩)O
1、使用工具
主要工具有:pycharm64.exe + Python 3.6 64-bit + MySQL + Navicat for MySQL(輔助工具)
主要內容是實現此頁面所有的static文件、templates文件與py文件:
2、完成基本的頁面設計
①.導航條(父模板)
②.登陸界面
③.注冊界面
④.發布問答界面
3、涉及到的第三方庫和Flask & 概覽
主py文件:
manage.py(用於數據庫遷移):
Flask
from flask import Flask app = Flask(__name__) # 創建Flask對象 @app.route('/lin/') # 跳轉簡單測試。 def lin(): return 'lin' if __name__ == '__main__': app.run(debug=True)
4、加載靜態文件,父模板與其他界面的繼承
①.url_for運用
from flask import url_for
跳轉后端請求:
<a class="navbar-brand" href="{{ url_for('daohang') }}">首頁</a> <a href="{{ url_for('yonghu',username_id=userid,tag=1) }}">個人信息</a></li>
加載靜態文件(可用於加載css, js, image文件):
<link rel="stylesheet" href="{{ url_for('static',filename='css/daohang.css') }}"> <script src="{{ url_for('static',filename='js/daohang.js') }}"></script>
②.繼承和擴展
目的在於把一些公共的代碼放在父模板中,避免每個模板寫同樣的內容。
子模板繼承父模板。
父模板提前定義好子模板可以實現一些自己需求的位置及名稱,子模板在相同名繼承塊中寫代碼實現自己需求。
注意{% block %}{% endblock %}里的命名。
{% extends 'daohang.html' %} {% block denglutitle %}{% endblock %} {% block dengluhead %}{% endblock %} {% block daohangbody %}{% endblock %}
5、數據庫連接池
運用工具:MySQL + Navicat for MySQL(輔助工具)
①.安裝與配置:
下載安裝MySQL數據庫
下載安裝Navicat for MySQL
下載安裝第三方庫MySQL-python 中間件(pip install flask-sqlalchemy (Python的ORM框架SQLAlchemy))
②.運用可是化工具Navicat for MySQL創建數據庫
③.數據庫配置信息config.py
import os DEBUG = True SECRET_KEY = os.urandom(24) DIALECT = 'mysql' DRIVER = 'mysqldb' USERNAME = 'root' PASSWORD = 'ROOT' HOST = '127.0.0.1' PORT = '3306' DATABASE = 'mis_db' # 配置和數據庫的連接信息 SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:@localhost/mis_db?charset=utf8' SQLALCHEMY_TRACK_MODIFICATIONS = False
④.建立mysql和app的連接
from flask import Flask from flask_sqlalchemy import SQLAlchemy import config app = Flask(__name__) # 創建Flask對象 app.config.from_object(config) # 關聯config.py文件進來 db = SQLAlchemy(app) # 建立和數據庫的關系映射 class Comment(db.Model): __tablename__ = 'comment' id = db.Column(db.Integer, primary_key=True, autoincrement=True) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) fabu_id = db.Column(db.Integer, db.ForeignKey('fabu.id')) creat_time = db.Column(db.DateTime, default=datetime.now) detail = db.Column(db.Text, nullable=False) fabu = db.relationship('Fabu', backref=db.backref('comments', order_by=creat_time.desc)) # order_by=creat_time.desc按時間降序 author = db.relationship('User', backref=db.backref('comments')) db.create_all() # 測試是否連接成功 @app.route('/lin/') # 跳轉測試。 def lin(): return 'lin' if __name__ == '__main__': app.run(debug=True)
⑤.創建用戶模型
class User(db.Model): # 創建類User ... class Fabu(db.Model): ... class Comment(db.Model): ...
6、通過用戶模型,對數據庫進行增刪改查
# 插入功能 user = User(username='15',password='12') db.session.add(user) db.session.commit() # 查詢功能 user=User.query.filter(User.username=="15").first() print(user.username,user.password) # 修改功能 user=User.query.filter(User.username=="15").first() user.password='888' db.session.commit() # 刪除功能 user=User.query.filter(User.username=="15").first() db.session.delete(user) db.session.commit()
7、完成注冊功能
①.html文件:
<form>中設置 action和method="post"
<input> 中設置 name
<button>中onclick="return fnLogin()"
②.js文件:
運用一系列if函數判斷
onclick函數return True時才提交表單,return False時不提交表單。
③.主py文件中:
from flask import request, redirect, url_for
# 跳轉注冊。 @app.route('/zhuce/', methods=['GET', 'POST']) # methods定義它有兩種請求方式,因為它在表單的請求是post,類似我們在idea中的sava請求模式 def zhuce(): if request.method == 'GET': return render_template('zhuce.html') else: username = request.form.get('user') # post請求模式,安排對象接收數據 password = request.form.get('pass') nickname = request.form.get('nickname') user = User.query.filter(User.username == username).first() # 作查詢,並判斷 if user: return u'該用戶已存在' else: user = User(username=username, password=password, nickname=nickname) # 將對象接收的數據賦到User類中,即存到數據庫 db.session.add(user) # 執行操作 db.session.commit() return redirect(url_for('denglu')) # redirect重定向
8、完成登陸功能
類似注冊功能
# 跳轉登陸。 @app.route('/denglu/', methods=['GET', 'POST']) # methods定義它有兩種請求方式 def denglu(): if request.method == 'GET': return render_template('denglu.html') else: username = request.form.get('user') # post請求模式,安排對象接收數據 password = request.form.get('pass') user = User.query.filter(User.username == username).first() # 作查詢,並判斷 if user: # 判斷用戶名 if user.check_password(password): # 判斷密碼 session['user'] = username # 利用session添加傳回來的值username session.permanent = True # 設置session過期的時間 return redirect(url_for('daohang')) else: return u'用戶密碼錯誤' else: return u'用戶不存在,請先注冊'
(補充)session功能:
from flask import session
①.操作字典一樣操作`session`:
session['user'] = username # 利用session添加傳回來的值username session.permanent = True # 設置session過期的時間 session.get('user'):
②.放在上下文處理器中可以在任何模板頁面中調用:
@app.context_processor # 上下文處理器,定義變量然后在所有模板中都可以調用,類似idea中的model def mycontext(): user = session.get('user') if user: return {'sessionusername': user} # 包裝到username,在所有html模板中可調用 else: return {} # 返回空字典,因為返回結果必須是dict
9、登錄后更新導航
①.用上下文處理器app_context_processor定義函數,把登陸時定義的session get進來
@app.context_processor # 上下文處理器,定義變量然后在所有模板中都可以調用,類似idea中的model def mycontext(): user = session.get('user') if user: return {'sessionusername': user} # 包裝到username,在所有html模板中可調用 else: return {} # 返回空字典,因為返回結果必須是dict
②.在父模板中更新導航,利用if函數判斷,插入登錄狀態判斷代碼
{% if sessionusername %} <li><a href="#" onclick="">{{ sessionusername }}</a></li> <li><a href="{{ url_for('logout') }}" onclick=""><span class="glyphicon glyphicon-log-out"></span> 注銷</a></li> {% else %} <li><a href="{{ url_for('denglu') }}" onclick=""><span class="glyphicon glyphicon-log-in"></span> 登陸</a> </li> <li><a href="{{ url_for('zhuce') }}" onclick=""><span class="glyphicon glyphicon-user"></span> 注冊</a></li> {% endif %}
注意用{% ... %}表示指令,區分后台和前端的if判斷。
{{ }}表示變量
③.完成注銷功能
清楚session並跳轉
# 跳轉注銷。 @app.route('/logout') def logout(): session.clear() # 注銷時刪除所有session return redirect(url_for('daohang'))
10、完成發布功能(和登陸注冊類似)
①.編寫請求登錄的裝飾器:
# 跳轉某頁面之前先進行登錄。定義decorator可以增強函數功能,裝飾器本身是函數,入參是函數,返回值也是函數 def loginFirst(fabu): @wraps(fabu) # 加上wraps,它可以保留原有函數的__name__,docstring def wrapper(*args, **kwargs): # 定義wrapper函數將其返回,用*args, **kwargs把原函數的參數進行傳遞 if session.get('user'): # 只有經過登陸,session才能記住並get到值 return fabu(*args, **kwargs) else: return redirect(url_for('denglu')) return wrapper
②.應用裝飾器:
@loginFirst # 將decorator定義的增強函數放在待增強函數定義的上面
@app.route('/fabu/', methods=['GET', 'POST']) # methods定義它有兩種請求方式 @loginFirst # 將decorator定義的增強函數放在待增強函數定義的上面 def fabu():
③.建立發布內容的對象關系映射
class Fabu(db.Model): __tablename__ = 'fabu' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(100), nullable=False) detail = db.Column(db.Text, nullable=False) creat_time = db.Column(db.DateTime, default=datetime.now) # 提交時間會自己賦值 author_id = db.Column(db.Integer, db.ForeignKey('user.id')) # 數據類型是db.Integer,db.ForeignKey參數指定外鍵是哪個表中哪個id author = db.relationship('User', backref=db.backref('fabu')) # 建立關聯,其author屬性將返回與問答相關聯的用戶實例,相當於數據庫中的表連接 # 第一個參數表明這個關系的另一端是哪個類,第二個參數backref,將向User類中添加一個fabu屬性,從而定義反向關系,這一屬性可訪問Fabu類,獲取的是模型對象
④.完成發布函數,保存數據庫,重定向到首頁
# 跳轉發布。 @app.route('/fabu/', methods=['GET', 'POST']) # methods定義它有兩種請求方式 @loginFirst # 將decorator定義的增強函數放在待增強函數定義的上面 def fabu(): if request.method == 'GET': return render_template('fabu.html') else: title = request.form.get('title') # post請求模式,安排對象接收數據 detail = request.form.get('detail') author_id = User.query.filter( User.username == session.get('user')).first().id # 將session get到的user進行查詢並取出id放到外鍵author_id中 fabu = Fabu(title=title, detail=detail, author_id=author_id) # 將對象接收的數據賦到Fabu類中,即存到數據庫 db.session.add(fabu) # 執行操作 db.session.commit() # 提交到數據庫 return redirect(url_for('daohang')) # redirect重定向
11、在首頁顯示問答列表(可自行選擇顯示內容,本文以顯示問答內容為例)
①.在首頁添加顯示問答的無序列表
<div class="col-md-6 column s1"> <h3 class="text-center">發布</h3> <ul class="list-unstyled"> {% for foo in fabus %} <li class="list-group-item-success"> <a href="{{ url_for('yonghu',username_id=foo.author_id,tag=1) }}"><span class="glyphicon glyphicon-fire"></span>{{ foo.author.username }}</a> <h4 class="text-center"><a href="{{ url_for('fabuview',fabu_id=foo.id) }}">{{ foo.title }}</a></h4> <span class="badge pull-right">{{ foo.creat_time }}</span> <br> <p>{{ foo.detail }}</p> </li> {% endfor %} </ul> </div>
②.用字典模板向首頁傳遞參數並完成發布詳情頁前端html
(1)首頁列表顯示全部問答:
將數據庫查詢結果傳遞到前端頁面
'fabus': Fabu.query.all()
(2)前端頁面循環顯示整個列表。
{% for foo in fabus %}
{{ foo.author.username }}
{{ foo.title }}
{{ foo.creat_time }}
{{ foo.detail }}
{% endfor %}
(3)問答排序
order_by('-creat_time')
(4)完成問答詳情頁布局:
包含問答的全部信息
評論區
以往評論列表顯示區。
(5)在首頁點擊問答標題,鏈接到相應詳情頁。
<h4 class="text-center"><a href="{{ url_for('fabuview',fabu_id=foo.id) }}">{{ foo.title }}</a></h4>
# 跳轉發布詳情 @app.route('/fabuview/<fabu_id>') # 和idea的update一樣,將id帶到控制器 def fabuview(fabu_id): fa = Fabu.query.filter(Fabu.id == fabu_id).first() # 根據主頁帶回來的id查詢出整條元組記錄,丟進fa comments = Comment.query.filter(Comment.fabu_id == fabu_id).all() # 根據帶回來的Fabu的id在Comment查詢出所有評論 return render_template('fabuview.html', fa=fa, comments=comments) # 把值fa丟進鍵fa,在fabuview.html頁面調用
12、從首頁問答列表標題鏈接到詳情頁
①.首頁標題的標簽做帶參數的鏈接。
href="{{ url_for('fabuview',fabu_id=foo.id) }}"
②.主PY文件寫視圖函數,帶id參數。
# 跳轉發布詳情 @app.route('/fabuview/<fabu_id>') # 和idea的update一樣,將id帶到控制器 def fabuview(fabu_id): fa = Fabu.query.filter(Fabu.id == fabu_id).first() # 根據主頁帶回來的id查詢出整條元組記錄,丟進fa comments = Comment.query.filter(Comment.fabu_id == fabu_id).all() # 根據帶回來的Fabu的id在Comment查詢出所有評論 return render_template('fabuview.html', fa=fa, comments=comments) # 把值fa丟進鍵fa,在fabuview.html頁面調用
③.在詳情頁將數據顯示在恰當的位置,即調用后端字典模型。
{{ fa.title }}
{{ fa.author.username }}
{{ fa.creat_time }}
{{ fa.detail }}
13、實現發布評論,並顯示評論區
①.前端html模板。
<div>
<textarea></textarea>
<button></button>
</div>
②.后台視圖函數
# 跳轉評論 @app.route('/comment/', methods=['POST']) @loginFirst # 裝飾器,跳轉某頁面之前先進行登錄 def comment(): detail = request.form.get('pinglun') # post請求模式,安排對象接收數據 author_id = User.query.filter(User.username == session.get('user')).first().id fabu_id = request.form.get('fa_id') comment = Comment(detail=detail, author_id=author_id, fabu_id=fabu_id) # 將對象接收的數據賦到Comment類中,即存到數據庫 db.session.add(comment) # 執行操作 db.session.commit() # 提交到數據庫 return redirect(url_for('fabuview', fabu_id=fabu_id)) # 重定向到fabuview請求時要帶fabu_id
③.顯示評論條數
其實類似於首頁顯示發布內容
{% for foo in fa.comments %}
{{ foo.author.username }}
{{ foo.creat_time }}
{{ foo.detail }}
{% endfor %}
14、完成個人中心相關信息
①.個人中心—視圖函數帶標簽頁面參數tag(在if判斷時判斷tag,可以三個頁面跳轉同一請求函數)
# 跳轉用戶詳情 @app.route('/yonghu/<username_id>/<tag>') # 為了把頁面分開,我們在html頁面傳了一個tag參數 def yonghu(username_id, tag): user = User.query.filter(User.id == username_id).first() context = { 'userid': user.id, 'username': user.username, 'fabus': user.fabu, 'comments': user.comments } # 根據tag的不同去到不同頁面,一個請求跳轉3個不同頁面 if tag == '1': return render_template('yonghu1.html', **context) elif tag == '2': return render_template('yonghu2.html', **context) else: return render_template('yonghu3.html', **context)
②.個人中心—導航標簽鏈接增加tag參數
<ul class="nav nav-pills"> <li class="active" role="presentation"><a href="{{ url_for('yonghu',username_id=userid,tag=1) }}">個人信息</a></li> <li class="active" role="presentation"><a href="{{ url_for('yonghu',username_id=userid,tag=2) }}">發布信息</a></li> <li class="active" role="presentation"><a href="{{ url_for('yonghu',username_id=userid,tag=3) }}">評論信息</a></li> </ul>
③.個人信息,發布信息,評論信息等頁面全部繼承到個人中心頁,個人中心頁再繼承到首頁
(1)個人中心頁:
{% block yonghubody %}{% endblock %}
(2)個人信息,發布信息,評論信息頁:
{% block yonghubody %}個人信息內容html{% endblock %}
{% block yonghubody %}發布信息內容html{% endblock %}
{% block yonghubody %}評論信息內容html{% endblock %}
④.個人中心—有鏈接到個人中心頁面的url增加tag參數
<a href="{{ url_for('yonghu',username_id=foo.author_id,tag=1) }}">
15、實現導航條中的搜索功能
①.搜索輸入框method為‘get’
<form class="form-inline" role="form" action="{{ url_for('search') }}" method="get">
</form>
②完成視圖函數search()
from sqlalchemy import or_, and_
# 跳轉首頁搜索 @app.route('/search/') def search(): sousuo = request.args.get('sousuo') # args獲取關鍵字,區別form fabus = Fabu.query.filter( or_( # 兩種查詢條件 Fabu.title.contains(sousuo), # contains模糊查 Fabu.detail.contains(sousuo) ) ).order_by('-creat_time') return render_template('daohang.html', fabus=fabus) # fabus要和原首頁數據模型一樣
16、密碼保護
from werkzeug.security import generate_password_hash,check_password_hash _password = db.Column(db.String(200), nullable=False) # 密碼加密內部使用 @property # 定義函數,需要用屬性時可以用函數代替 def password(self): # 密碼加密外部使用 return self._password @password.setter def password(self,row_password): # 密碼進來時進行加密,generate_password_hash是一個密碼加鹽哈希函數,生成的哈希值可通過check_password_hash()進行驗證。 self._password = generate_password_hash(row_password) def check_password(self,row_password): # check_password_hash函數用於驗證經過generate_password_hash哈希的密碼。若密碼匹配,則返回真,否則返回假。 result = check_password_hash(self._password,row_password) return result
密碼進來時進行加密,generate_password_hash是一個密碼加鹽哈希函數,生成的哈希值可通過check_password_hash()進行驗證。
check_password_hash函數用於驗證經過generate_password_hash哈希的密碼。若密碼匹配,則返回真,否則返回假。
登錄驗證:
把user.password ==passwodr,修改成user.check_password(password): # 判斷密碼
# 跳轉登陸。 @app.route('/denglu/', methods=['GET', 'POST']) # methods定義它有兩種請求方式 def denglu(): if request.method == 'GET': return render_template('denglu.html') else: username = request.form.get('user') # post請求模式,安排對象接收數據 password = request.form.get('pass') user = User.query.filter(User.username == username).first() # 作查詢,並判斷 if user: # 判斷用戶名 if user.check_password(password): # 判斷密碼 session['user'] = username # 利用session添加傳回來的值username session.permanent = True # 設置session過期的時間 return redirect(url_for('daohang')) else: return u'用戶密碼錯誤' else: return u'用戶不存在,請先注冊'
17、模型分離
為了方便管理,我們進行模型分離
主py:
from flask import Flask, render_template, request, redirect, url_for, session import config from functools import wraps from sqlalchemy import or_, and_ from models import User,Fabu,Comment from exts import db app = Flask(__name__) # 創建Flask對象 app.config.from_object(config) # 關聯config.py文件進來 db.init_app(app) # 建立和數據庫的關系映射
models.py:
from datetime import datetime from werkzeug.security import generate_password_hash,check_password_hash from exts import db class User(db.Model): # 創建類User __tablename__ = 'user' # 類對應的表名user id = db.Column(db.Integer, primary_key=True, autoincrement=True) # autoincrement自增長 username = db.Column(db.String(20), nullable=False) # nullable是否為空 _password = db.Column(db.String(200), nullable=False) # 密碼加密內部使用 nickname = db.Column(db.String(20), nullable=True) @property # 定義函數,需要用屬性時可以用函數代替 def password(self): # 密碼加密外部使用 return self._password @password.setter def password(self,row_password): # 密碼進來時進行加密,generate_password_hash是一個密碼加鹽哈希函數,生成的哈希值可通過check_password_hash()進行驗證。 self._password = generate_password_hash(row_password) def check_password(self,row_password): # check_password_hash函數用於驗證經過generate_password_hash哈希的密碼。若密碼匹配,則返回真,否則返回假。 result = check_password_hash(self._password,row_password) return result class Fabu(db.Model): __tablename__ = 'fabu' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(100), nullable=False) detail = db.Column(db.Text, nullable=False) creat_time = db.Column(db.DateTime, default=datetime.now) # 提交時間會自己賦值 author_id = db.Column(db.Integer, db.ForeignKey('user.id')) # 數據類型是db.Integer,db.ForeignKey參數指定外鍵是哪個表中哪個id author = db.relationship('User', backref=db.backref('fabu')) # 建立關聯,其author屬性將返回與問答相關聯的用戶實例,相當於數據庫中的表連接 # 第一個參數表明這個關系的另一端是哪個類,第二個參數backref,將向User類中添加一個fabu屬性,從而定義反向關系,這一屬性可訪問Fabu類,獲取的是模型對象 class Comment(db.Model): __tablename__ = 'comment' id = db.Column(db.Integer, primary_key=True, autoincrement=True) author_id = db.Column(db.Integer, db.ForeignKey('user.id')) fabu_id = db.Column(db.Integer, db.ForeignKey('fabu.id')) creat_time = db.Column(db.DateTime, default=datetime.now) detail = db.Column(db.Text, nullable=False) fabu = db.relationship('Fabu', backref=db.backref('comments', order_by=creat_time.desc)) # order_by=creat_time.desc按時間降序 author = db.relationship('User', backref=db.backref('comments')) # db.create_all() # 測試是否連接成功
exts.py:
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # 建立和數據庫的關系映射
這里引進多一個exts.py主要使models.py和主py不要進入死循環狀態
(備注:在這里小編發現一個問題,模型分離要在數據庫表建出后分離,刪除數據庫表或換機后不會自動再創建表,頁面出現報錯,也就是說只能在數據庫表不變動下使用它,可能由於小編是菜鳥,暫時沒有找到解決方法,慎用)
18、數據遷移
數據遷移應用於模型增加屬性刪除屬性,增加模型刪除模型或修改屬性數據類型時使用,可以極大程度方便我們的操作,例如在刪除模型時不用去數據庫刪除表格再重新運行,修改模型屬性數據類型時不會出現數據刪除后重建等麻煩。
manage.py:
from flask_script import Manager from flask_migrate import Migrate,MigrateCommand # flask_migrate是一個數據遷移框架,需要通過flask_script來操作 from untitled import db from untitled import app from untitled import User, Fabu, Comment manager = Manager(app) # Manager只有一個參數:一個Flask實例 migrate = Migrate(app, db) # 使用Migrate綁定app和db # 添加遷移腳本命令 manager.add_command('db',MigrateCommand) # 加入命令,命令行輸入python manage.py db migrate if __name__ == '__main__': manager.run() # 啟動Manager實例接收命令行中的命令 ''' 生成初始化遷移環境,只運行一次 python manage.py db init 生成遷移文件,模型改變了需要執行 python manage.py db migrate 映射到數據庫表中 python manage.py db upgrade '''
詳情見注釋,這里不做多解釋
nick是新增的屬性
PS:以上即是本菜鳥一學期以來所學的內容和實現的功能,讀者可以根據自己的需求閱讀並分享使用。最后感謝杜老師和幫助過我的同學,望各位讀者再接再厲( ̄▽ ̄)"