總結Python+Flask+MysqL的web建設技術過程


 

一、個人學期總結

 

    本人在一學期時間內學習並實現基於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,但一開始都會用一些蠢辦法,用空格代替或者用&nbsp去填充,雖說不是最佳的解決方法,但也達到了同樣的效果,在后端建設過程中我們引入了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:以上即是本菜鳥一學期以來所學的內容和實現的功能,讀者可以根據自己的需求閱讀並分享使用。最后感謝杜老師和幫助過我的同學,望各位讀者再接再厲( ̄▽ ̄)"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM