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

1、前言(我的學期總結)

    我的總結一下這學期對於Python+Flask+MysqL的web建設技術過程的學習體會,Flask小辣椒框架相對於其餘框架而言,更加穩定,不會有莫名其妙的錯誤,容錯性強,運行效果好,報錯信息明瞭, Python是近幾年流行起來的語言,簡單易懂,很好上手,強大的庫讓咱們能夠站在巨人的肩膀上寫代碼,應證了人們常說的那句「人生苦短,我用python」,MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 是最流行的關係型數據庫管理系統之一,基本功能都能準確無誤的給予數據支持。在本次建站過程當中,前端界面採用的是html、css、JavaScript,後端採用python做爲支持。
javascript

    從一開始接觸的是turtle庫繪製圖形,在沒有接觸基本語法的狀況下,覺得會由於基礎不紮實而學起來吃力,然而,turtle庫的學習,打開了咱們對python的學習興趣的閘門,這是一門多麼簡潔實用的語言,python的第三方庫是多麼的強大,逐漸的,在對庫的使用中熟悉了python的語法,學起來一點也不吃力,有了html基礎,加上Bootstrap框架的引用,就能夠製做出一個靜態頁面,再有了python基礎以及鏈接數據庫的知識,就能夠完成web建站了。css

    本次的mysql運用的是遠程數據庫,便於搭建環境和數據存儲,可視化軟件是SQLyog。html

2、使用工具

 主要工具備:pycharm64.exe + Python 3.6 64-bit + MySQL +SQLyog(輔助工具)前端

 

 

 

 

 

 

 Python下載地址https://www.python.org/downloads/java

MySQL下載地址:https://www.mysql.com/downloads/python

Pycharm下載地址:https://www.jetbrains.com/pycharm/download/#section=windowsmysql

 

 3、完成基本的頁面設計

①導航條git

②登錄界面github

③註冊界面web

 

④發佈問答界面

 

 4、Flask & 概覽

一、初始化
在這章,你將學到Flask應用程序的不一樣部分。同時,你將編寫和運行你的第一個Flask web應用程序。

全部的Flask應用程序都必須建立一個 應用程序實例 。使用web服務器網關接口協議將全部從客戶端接收的請求傳遞給這個對象處理。這個應用程序實例就是Flask類的一個對象,一般使用下面的方式建立:

 
1
2
from flask import Flask
app = Flask(__name__)

Flask類構造函數惟一須要的參數就是應用程序的主模塊或包。對於大多數應用程序,Python的__name__變量就是那個正確的、你須要傳遞的值。

注:對於Flask開發者來講,傳給Flask應用程序構造函數的name參數是比較容易弄混淆的。Flask使用這個參數來肯定應用程序的根目錄,這樣之後能夠相對這個路徑來找到資源文件。
稍後你能夠看到更復雜的應用程序實例初始化,可是對於簡單應用程序這些已經足夠了。

二、路由和視圖函數
客戶端例如web瀏覽器發送 請求 給web服務,進而將它們發送給Flask應用程序實例。應用程序實例須要知道對於各個URL請求須要運行哪些代碼,因此它給Python函數創建了一個URLs映射。這些在URL和函數之間創建聯繫的操做被稱之爲 路由 。

在Flask應程序中定義路由的最便捷的方式是經過顯示定義在應用程序實例之上的app.route裝飾器,註冊被裝飾的函數來做爲一個路由。下面的例子會演示怎樣使用裝飾器來申明一個路由:

 
1
2
3
@app .route( '/' )
def index():
  return '<h1>Hello World!</h1>'

注:裝飾器是Python語言的標準特性;它們能夠以不一樣方式改變函數的行爲。一個常見的模式是使用裝飾器來註冊函數做爲一個事件處理程序。
在上一個示例給應用程序的根URL註冊index()函數做爲事件的處理程序。若是這個應用程序被部署在服務器上並綁定了 www.example.com 域名,而後在你的瀏覽器地址欄中輸入 http://www.example.com 將觸發index()來運行服務。客戶端接收到的這個函數的返回值被稱爲 響應 。若是客戶端是web瀏覽器,響應則是顯示給用戶的文檔。

相似於index()的函數被稱做 視圖函數 。經過視圖返回的響應能夠是簡單的HTML內容的字符串,但它也能夠市更復雜的形式,正如您將看到的。

注:響應字符串嵌入在Python代碼中致使代碼難以掌控,在此只是介紹響應的概念。你將在第三章學習正確的方法來生成響應。
若是你注意到你天天使用的一些網站URLs如何造成的,你將會發現不少都有變量。例如,你的Facebook我的信息頁的URL是 http://www.facebook.com/<username> ,因此你的用戶名是它的一部分。Flask在路由裝飾器中使用特殊的語法支持這些類型的URLs。下面的示例定義了一個擁有動態名稱組件的路由:

 
1
2
3
@app .route( '/user/<name>' )
def user(name):
  return '<h1>Hello, %s!</h1>' % name

用尖括號括起來的部分是動態的部分,因此任何URLs匹配到靜態部分都將映射到這個路由。當視圖函數被調用,Flask發送動態組件做爲一個參數。在前面的示例的視圖函數中,這個參數是用於生成一個個性的問候做爲響應。

在路由中動態組件默認爲字符串,可是能夠定義爲其餘類型。例如,路由/user/<int:id>只匹配有一個整數在id動態段的URLs。Flask路由支持int、float和path。path一樣是字符串類型,但並不認爲斜槓是分隔符,而認爲它們是動態組件的一部分。

三、服務啓動
應用程序實例有一個run方法用於啓動Flask集成的web服務:

 
1
2
if __name__ = = '__main__' :
  app.run(debug = True )

__name__ == '__main__'在此處使用是用於確保web服務已經啓動當腳本被當即執行。當腳本被另外一個腳本導入,它被看作父腳本將啓動不一樣的服務,因此app.run()調用會被跳過。

一旦服務啓動,它將進入循環等待請求併爲之服務。這個循環持續到應用程序中止,例如經過按下Ctrl-C。

有幾個選項參數能夠給app.run()配置web服務的操做模式。在開發期間,能夠很方便的開啓debug模式,將激活 debugger 和 reloader 。這樣作是經過傳遞debug爲True來實現的。

注:Flask提供的web服務並不用於生產環境。你將在十七章學習生產環境的web服務。

四、一個完整的應用程序
在上一節,你學習了Flask web應用程序的不一樣部分,如今是時候寫一個了。整個 hello.py 應用程序腳本只不過將前面描述的三個部分結合在一個文件中。應用程序示例2-1所示。

示例 hello.py:一個完整的Flask應用程序

 
1
2
3
4
5
6
7
8
9
10
11
12
13
from flask import Flask
app = Flask(__name__)
 
@app .route( '/' )
def index():
  return '
 
<h1>Hello World!< / h1>
 
'
 
if __name__ = = '__main__' :
  app.run(debug = True )

 

 通過這個過程,一個完整的Flask應用程序就搭建起來了。

5、加載靜態文件,父模板與其餘界面的繼承

 1.加載靜態文件

   <script language="javascript" type="text/javascript" src="{{ url_for('static',filename="js/basic.js") }}"></script>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename="css/basic.css") }}">
 

2.父模板的設置

<!DOCTYPE>
<html>
<head>
    <meta charset="utf-8">
  <title>{% block title %}{% endblock %}</title>
 
</head>
<body id="myBody" style="min-width: 1500px;" background="{{ url_for('static',filename="img/timg1.jpg") }}"> {% block aa %}{% endblock %}  </body> </html>

3.子模板繼承

主頁:

{% extends 'base.html' %}
{% block title %} 主頁{% endblock %}
{% block aa %}
{% endblock %}

註冊:

  {% extends 'base.html'%}
{% block title %} 註冊{% endblock %}
  {% block aa %}
 {% endblock %}

登陸:

{% extends 'base.html' %}
{% block title %} 登陸{% endblock %}
{% block aa %}
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename="css/login.css") }}">
    <script language="javascript" type="text/javascript" src="{{ url_for('static',filename="js/login.js") }}"></script> {% endblock %}

我的父模板:

{% extends 'base.html' %}
{% block title %} 我的中心{% endblock %}

{% block aa %}

{% block user %}{% endblock %}
 </div> {% endblock %}

我的子模板:

{% extends 'user.html' %}

{% block user %}

{% endblock %}

問答頁:

{% extends 'base.html' %}
{% block title %} 互動{% endblock %}
{% block aa %}
{% endblock %}

 

6、數據庫鏈接池

數據庫工具:mysql

import os
DEBUG=True SECRET_KEY=os .urandom(24) # # DIALECT='mysql' # DRIVER='mysqldb' # USERNAME='yu' # PASSWORD='bozhi' # HOST='www.decade.wang' # PORT='3306' # DATABASE='python' 
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://yu:bozhi@www.decade.wang:3306/decade?charset=utf8'
SQLALCHEMY_TRACK_MODIFICATIONS = False

 

創建鏈接:

主py

from werkzeug.security import generate_password_hash,check_password_hash
from datetime import datetime from exts import db class User(db.Model): __tablename__ = 'user' # 創建一個表user id = db.Column(db.Integer,primary_key=True,autoincrement=True) username = db.Column(db.String(20),nullable=False) _password = db.Column(db.String(200),nullable=False) image = db.Column(db.String(100)) say = db.Column(db.String(50)) @property def password(self):#外部使用 return self._password @password.setter def password(self,row_password): self._password=generate_password_hash(row_password) def check_password(self,row_password): result=check_password_hash(self._password,row_password) return result #db.create_all() # 創建一表question class Question(db.Model): __tablename__ = 'question' 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')) author=db.relationship('User',backref=db.backref('question')) classify=db.Column(db.Enum('散文拾貝', '心靈雞湯','笑談風聲', '爲所欲爲'),nullable=False) click = db.Column(db.INT, default=0) class Comment(db.Model): __tablename__ = 'comment' # 創建一個表log id = db.Column(db.Integer,primary_key=True,autoincrement=True) author_id = db.Column(db.Integer,db.ForeignKey('user.id')) question_id = db.Column(db.Integer,db.ForeignKey('question.id')) creat_time = db.Column(db.DateTime,default=datetime.now) detail = db.Column(db.Text,nullable=False) question = db.relationship('Question', backref=db.backref('comment',order_by=creat_time.desc)) author=db.relationship('User',backref=db.backref('comment')) #db.create_all()

exts

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

 

7、經過用戶模型,對數據庫進行增刪改查

添加數據
user=User(username='yujiujiu2',password='11111') db.session.add(user) db.session.commit() 添加數據 comment=Comment(detail='6666666') db.session.add(comment) db.session.commit() 查找數據 user=User.query.filter(User.username=='yujiujiu').first() print(user.username,user.password) 修改數據 user=User.query.filter(User.username=='yujiujiu').first() user.password='666667' print(user.username,user.password) db.session.commit() 刪除數據 user=User.query.filter(User.username=='yujiujiu2').first() db.session.delete(user) db.session.commit()

 

8、完成註冊功能

 

1.js文件: onclick函數return True時才提交表單,return False時不提交表單。

 

複製代碼
 function miao(){
        var oUname=document.getElementById("uname");
        var oUpass=document.getElementById("upass");
        var oUpass2=document.getElementById("upass2");
        var oError=document.getElementById("error_box");
        var isError=true;
        oError.innerHTML="<br>"
    if (oUname.value.length<6 || oUname.value.length>12){
     oError.innerHTML="用戶名6-12位";
     isError=false;
     return isError;
    } else if((oUname.value.charCodeAt(0)>=48)&&(oUname.value.charCodeAt(0)<=57)){
       oError.innerHTML="first letter";
       isError=false;
       return isError;
    }
    else for(var i=0;i<oUname.value.length;i++) {
            if (((oUname.value.charCodeAt(i) < 48) || (oUname.value.charCodeAt(i) > 57)) && ((oUname.value.charCodeAt(i) < 97) || (oUname.value.charCodeAt(i) > 122))) {
                oError.innerHTML = "only letter or number";
                isError=false;
                return isError;
            }

        }

if (oUpass.value.length<6 || oUpass.value.length>12){
   oError.innerHTML="密碼6-12位";
   return false;
}
    else if (oUpass.value!==oUpass2.value){
        oError.innerHTML="兩次密碼不一致";
        return false;
    }
    return true;
    // window.alert("註冊成功!")

    }
 function mySwitch() {
    var oBody = document.getElementById("myBody");

    var oOnOff = document.getElementById("myOnOff");
    var ogui = document.getElementById("gui");
    if (oOnOff.src.match('bulbon')) {

        oOnOff.src = "http://www.runoob.com/images/pic_bulboff.gif";
        oBody.style.backgroundColor = "black";
        oBody.background="../static/img/h.jpg"
        oBody.style.color = "white";
        ogui.src = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509563443074&di=b1bbb3f5714a580e2211e281124636c2&imgtype=0&src=http%3A%2F%2Fpic15.nipic.com%2F20110709%2F7854247_221301558161_2.jpg";
    } else {
        oOnOff.src = "http://www.runoob.com/images/pic_bulbon.gif";
        oBody.style.backgroundColor = "white";
        oBody.style.color = "black";
        ogui.src = "";
        oBody.background="../static/img/timg1.jpg"
    }
}
複製代碼

 

運行結果:

 

 

 

2.html文件:

    1. <form>中設置 action和method="post"
    2. <input> 中設置 name
複製代碼
  {% extends 'basic.html'%}
  {% block aa %}
    <link rel="stylesheet" type="text/css" href="{{url_for('static',filename="css/zhuce.css")  }}">
        <script language="javascript" type="text/javascript" src="{{url_for('static',filename="js/zhuce.js")  }}"></script>
<div id=mao ><p></p>
    <div id="header"><h2 align="center"></h2></div>
    <div id="content" >

        <form action="{{ url_for('zhuce')}}" method="post"><br/>
            <div class="form-group">
                <label for="uname" class="col-sm-2 control-label">Username:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="uname" name="username"
                           placeholder="make your username"><br>
                </div>
            </div>
            <div class="form-group">
                <label for="upass" class="col-sm-2 control-label">Password:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="upass" name="password"
                           placeholder="make your password"><br>
                </div>
            </div>
            <div class="form-group">
                <label for="upass2" class="col-sm-2 control-label">AgainPass:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="upass2"
                           placeholder="again your password"><br>
                </div>
            </div>
<div class="form-group1"><label for="question" >SomethingSay</label>
<textarea class="col-sm-10" rows="3" id="question" name="say"></textarea><br><br><br><br>
</div>
            <div >
            <br>  &nbsp &nbsp <input type="radio" name="role" value="stu">student
            <input id="tea" type="radio" name="role" value="tea">teacher<br/>
            </div>
            <div id="error_box"  ></div>
            <div align="center">
               <input id="input_box" type="button" class="btn btn-default btn-lg active" value="註冊" onclick="miao()">
             </div>
          </form>
</div>
</div>

  {% endblock %}
複製代碼

 

3.主py文件中:

    1. from flask import  request, redirect, url_for
    2. @app.route('/regist/', methods=['GET', 'POST’])
@app.route('/zhuce/',methods=['GET','POST'])
def zhuce():
    if request.method=='GET':
        return render_template('zhuce.html')
    else:
        username=request.form.get('username')
        password=request.form.get('password')
        say=request.form.get('say')
        user=User.query.filter(User.username==username).first()
        #判斷用戶名是否存在
        if user:
            return u' username existed'
        else:
            user=User(username=username,password=password,say=say)
            db.session.add(user)
            db.session.commit()
            return redirect(url_for('login'))
#從新定向到登陸頁

 

運行結果:

 

9、完成登錄功能

登陸功能完成:

1.js:設置return

同註冊,onclick函數return True時才提交表單,return False時不提交表單。

2.html:設置

  1. form
  2. input

 

   <form action="{{ url_for('login')}}" method="post"><br/>



            <div class="form-group">
                <label for="uname" class="col-sm-2 control-label">Username:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="uname" name="username"
                           placeholder="input your username"><br>
                </div>


            </div>
            <div class="form-group">
                <label for="upass" class="col-sm-2 control-label">Password:</label>
                <div class="col-sm-10">
                    <input type="password" class="form-control" id="upass" name="password"
                           placeholder="input your password"><br>
                </div>
            </div>

           <div >
            <br> &nbsp &nbsp &nbsp <input type="radio" name="role" value="stu">student&nbsp
            <input id="tea" type="radio" name="role" value="tea">teacher<br/><br/>
            </div>

            <div align="center">
            <input id="rem" type="checkbox" value="true"><span>remember me</span> &nbsp &nbsp &nbsp &nbsp<a href="http://help.clouddream.net/newsitem/277741776" target="_blank">Login problem</a><br/>
            <br>
            </div>
      <div id="error_box" ></div>
            <div align="center">
               <input id="input_box" type="submit" class="btn btn-default btn-lg active" value="登陸" onclick=" return miao()">
             </div>
          </form>

 

3.py:

  1. @app.route設置methods
  2. GET
  3. POST
    1. 讀取表單數據
    2. 查詢數據庫
      1. 用戶名密碼對:
        1. 記住用戶名
        2. 跳轉到首頁
      2. 用戶名密碼不對:
        1. 提示相應錯誤。
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    else:
        usern=request.form.get('username')
        passw=request.form.get('password')

        user=User.query.filter(User.username==usern).first()
        #判斷用戶名是否存在
        if user:
            session['user']=usern
            session.permanent=True
            if user.password==passw:
                return redirect(url_for('index'))
            else:
                return u' password error'
        else:
            return u' username  not existed'

 

10、登陸後更新導航

1.用上下文處理器app_context_processor定義函數

  1. 獲取session中保存的值
  2. 返回字典
#判斷是否登錄,有則在導航欄顯示用戶名
@app.context_processor
def mycontext():
    usern=session.get('user')
    if usern:
        return {'username':usern}
    else:
        return {}

 

2.在父模板中更新導航,插入登陸狀態判斷代碼。、

  1. 注意用{% ... %}表示指令。
  2. {{ }}表示變量
    {% if username %}

    <li><a href="#"><h2>{{ username }}</h2></a></li>
    <li><a href="{{ url_for('logout') }}"><h2>註銷</h2></a></li>
    {% else %}
    <li><a href="{{ url_for('login') }}"><h2>登陸</h2></a></li>
    <li><a href="{{ url_for('zhuce') }}"><h2>註冊</h2></a></li>
    {% endif %}
    <li><a href="#"><h2>聯繫我</h2></a></li>
</ul>


<img id="gui" onclick="mySwitch()" src="" width="1700px">

{% block aa %}{% endblock %}

 

3.完成註銷功能。

  1. 清除session
  2. 跳轉
#登出,清除session
@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

 

11、完成發佈功能

1.編寫要求登陸的裝飾器

from functools import wraps

def loginFirst(func): #參數是函數

@wraps(func)

      def wrapper(*args, ** kwargs): #定義個函數將其返回

          #要求登陸

          return func(*args, ** kwargs)

      return wrapper #返回一個函數

 

2.應用裝飾器,要求在發佈前進行登陸,登陸後可發佈。

@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():

 

#發佈前登錄裝飾器
def loginFirst(func):  # 參數是函數
    @wraps(func)
    def wrapper(*args, **kwargs):  # 定義個函數將其返回
        if session.get('user'):
            return func(*args, **kwargs)
        else:
            return redirect(url_for('login'))
    return wrapper  # 返回一個函數

 

3.創建發佈內容的對象關係映射。

class Question(db.Model):

4.完成發佈函數。

  保存到數據庫。

  重定向到首頁。

#登錄前驗證,進入評論進入問答頁
@app.route('/question/',methods=['GET','POST'])
@loginFirst
def question():
    if request.method=='GET':
        return render_template('question.html')
    else:
        title=request.form.get('title')
        detail = request.form.get('detail')
        author_id = User.query.filter(User.username ==session.get('user')).first().id
        question = Question(title=title, detail=detail, author_id=author_id)
        db.session.add(question)
        db.session.commit()
        return redirect(url_for('index'))

 

12、在首頁顯示問答列表

1. 在首頁添加顯示問答的列表,並定義好相應的樣式。

 

<ul class="list-group">

    <li class="list-group-item" style="width: 800px">

{#列表內容開始        #}
     <a class="wrap-img" href="#" target="_blank">
      <img src="http://www.bookmarkye.com/9.jpg" width="50px" >
    </a>
      <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
        <a  href="#" target="_blank">{{ user }}</a>
        <br>
         <a  href="#">{{ title }}</a>
     <span class="badge">發佈時間:{{time  }}</span>
              <p style="">{{ detail }}
    </p>


{#  列表內容結束      #}
    </li>


</ul>

2. 用字典向index.html傳遞參數。

@app.route('/')
def index():
    context={
        'user':'yubozhi',
        'title':'硬盤不是「背鍋俠」',
        'time':'2017-11-29',
        'detail':'昔日上將懸樑,今天硬盤入黨。說這話的是一位資深前媒體人。 光天化日之下,硬盤居然壞了!衆目睽睽之下,硬盤居然壞了!!大庭廣衆之下,硬盤居然壞了!!! 重要的事情說三遍!!! ...',

    }
    return render_template('basic.html',**context)

 

十3、從首頁問答列表標題連接到詳情頁

 

1.主PY文件寫視圖函數,帶id參數。 

代碼以下:

複製代碼
#進入每篇文章詳情頁
@app.route('/detail/<question_id>')
@loginFirst
def detail(question_id):
    quest=Question.query.filter(Question.id==question_id).first()

    context={
       'comments':Comment.query.order_by('-creat_time').all()

    }
    return render_template('detail.html',**context,ques=quest)
複製代碼

2.首頁標題的標籤作帶參數的連接。

代碼以下:

複製代碼
  {% for foo in questions %}


            <li class="list-group-item" style="width: 800px">

              
                <a class="wrap-img" href="#" target="_blank">
                    <img src="{{ foo.author.image }}" width="50px">
                </a>
                <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
                <a href="#" target="_blank">{{ foo.author.username }}</a>
                <br>
                <a href="{{ url_for('detail',question_id=foo.id) }}">{{ foo.title }}</a>

                <br>
                <span class="badge">發佈時間:{{ foo.creat_time }}</span>
                <p style="">{{ foo.detail }}
                </p>
{#                {{ url_for('usercenter',user_id=foo.author.id) }}#}
{#                <a href="#" target="_blank"><br>評論({{ foo.comments.length }})</a>#}


            </li>
        {% endfor %}
複製代碼

運行結果:

 

3.在詳情頁將數據的顯示在恰當的位置。

  1.首頁列表顯示所有問答:

  1. 將數據庫查詢結果傳遞到前端頁面 Question.query.all()
  2. 前端頁面循環顯示整個列表。
  3. 問答排序
@app.route('/')
def index():
    context={

        'questions':Question.query.order_by('-creat_time').all()

    }
    return render_template('basic.html',**context)

 

   2.完成問答詳情頁佈局:

  1. 包含問答的所有信息
  2. 評論區
  3. 以往評論列表顯示區。

代碼以下:

複製代碼
<div class="page-header">
    <h3>{{ ques.title }}<br><br>
    <small>做者:{{ ques.author.username }}&nbsp&nbsp&nbsp
    <span class="badge">{{ ques.creat_time }}</span>
        </small></h3>
</div>
            <p class="lead">{{ ques.detail }}</p>
            <hr>
            <form action="{{ url_for('comment') }}" method="post" style="">
                <div class="form-group">
                    <input type="text" value="{{ ques.id }}" name="question_id" hidden>
                    <input type="text" value="{{ user.id }}" name="author_id" hidden>
                    <textarea name="detail" class="form-control"  row="3" id="new-comment" placeholder="write your comment"></textarea>
                </div>
                <button type="submit" class="btn btn-default">發送</button>
            </form>
        <hr>
複製代碼

   3.在首頁點擊問答標題,連接到相應詳情頁。

#進入每篇文章詳情頁
@app.route('/detail/<question_id>')
def detail(question_id):
    quest=Question.query.filter(Question.id==question_id).first()
    return render_template('detail.html',ques=question_id)

 

 

運行結果:

 

4.創建評論的對象關係映射:

代碼以下:

複製代碼
class Comment(db.Model):
    __tablename__ = 'comment'
    # 創建一個表log
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    author_id = db.Column(db.Integer,db.ForeignKey('user.id'))
    question_id = db.Column(db.Integer,db.ForeignKey('question.id'))
    creat_time = db.Column(db.DateTime,default=datetime.now)
    detail = db.Column(db.Text,nullable=False)
    question = db.relationship('Question', backref=db.backref('comments'))
    author=db.relationship('User',backref=db.backref('comments'))
複製代碼

運行結果:

 

十4、實現發佈評論,並顯示評論區

代碼以下:

複製代碼
<h3>評論區:
{#    ({{ ques.comments.length }})#}
</h3><br>



<div class="basic_box" style="padding-bottom: 50px;">
    <ul class="list-group" style="margin-bottom: 10px">
      {% for qu in comments %}

            <li class="list-group-item" style="width: 800px">


                <a class="wrap-img" href="#" target="_blank">
                    <img src="{{ qu.author.image }}" width="50px">
                </a>
                <span class="glyphicon glyphicon-left" aria-hidden="true"></span>

                <br>
                <a href="#">{{ qu.author_id }}</a>
                <span class="badge">評論時間:{{ qu.creat_time }}</span>
                <p style="">{{ qu.detail }}
                </p>


            </li>
     {% endfor %}
複製代碼

運行結果:

 

十5、完成我的中心相關信息

1.我的中心的頁面佈局

html文件以下:

複製代碼
{% extends 'basic.html' %}
{% block title %} 我的中心{% endblock %}

{% block aa %}


<div class="container">
    <div class="row clearfix">
        <div class="col-md-2 column">
        </div>
        <div class="col-md-6 column">


<h1><img src="{{ img }}" width="50px">{{usern }}</h1>

    <br>所有問答


<div class="basic_box" style="padding-bottom: 50px;">
    <ul class="list-group">

           {% for qu in ques %}

            <li class="list-group-item" style="width: 800px">

<a class="wrap-img" href="#" target="_blank">
                    <img src="{{ qu.author.image }}" width="50px">
                </a>
                <span class="glyphicon glyphicon-left" aria-hidden="true"></span>
                <a href="{{ url_for('person',user_id=qu.author.id) }}" target="_blank">{{ qu.author.username }}</a>
                <br>
                <a href="{{ url_for('detail',question_id=qu.id) }}">{{qu.title }}</a>

                <br>
                <span class="badge">發佈時間:{{ qu.creat_time }}</span>
                <p style="">{{ qu.detail }}
                </p>
            </li>
     {% endfor %}
    </ul>
</div>

<h1><img src="{{ img }}" width="50px">{{usern }}</h1>
    <br>所有評論

<div class="basic_box" style="padding-bottom: 50px;">
    <ul class="list-group" style="margin-bottom: 10px">
      {% for qu in users %}


            <li class="list-group-item" style="width: 800px">


                <a class="wrap-img" href="#" target="_blank">
                    <img src="{{ qu.author.image }}" width="50px">
                </a>
                <span class="glyphicon glyphicon-left" aria-hidden="true"></span>

                <br>
                <a href="#">{{ qu.author.username }}</a>
                <span class="badge">評論時間:{{ qu.creat_time }}</span>
                <p style="">{{ qu.detail }}
                </p>


            </li>
     {% endfor %}
    </ul>
<br>
<br>
<h1><img src="{{ img }}" width="50px">{{usern }}</h1>
    <br>我的信息

<div class="basic_box" style="padding-bottom: 50px;">
    <ul class="list-group" style="margin-bottom: 10px">
{#      {% for qu in users %}#}


          <li class="list-group-item" style="width: 800px"> 用戶:{{ usern }}</li>
          <li class="list-group-item" style="width: 800px"> 編號:{{ id }}</li>
          <li class="list-group-item" style="width: 800px"> 問答數:{{ ques|length }}</li>
          <li class="list-group-item" style="width: 800px"> 評論數:{{ comment|length }}</li>

{#      {% endfor %}#}
    </ul>

        </div>
        <div class="col-md-4 column">
        </div>
    </div>
</div>

</div>

</div>

{% endblock %}
複製代碼

 

2.定義視圖函數def usercenter(user_id):

複製代碼
# 我的中心
@app.route('/person/<user_id>',methods=['GET','POST'])
def person(user_id):
    user = User.query.filter(User.id == user_id).first()

    context = {
        'img':user.image,
        'id':user_id,
        'usern':user.username,
        'ques': Question.query.filter(Question.author_id == user_id).order_by('-creat_time').all(),
        'users': Comment.query.filter(Comment.author_id == user_id).order_by('-creat_time').all(),
        'comment': user.comments
    }
    return render_template('person.html', **context)
複製代碼

 

3.向前端頁面傳遞參數

複製代碼
  context = {
        'img':user.image,
        'id':user_id,
        'usern':user.username,
        'ques': Question.query.filter(Question.author_id == user_id).order_by('-creat_time').all(),
        'users': Comment.query.filter(Comment.author_id == user_id).order_by('-creat_time').all(),
        'comment': user.comments
    }
複製代碼
複製代碼
<h1><img src="{{ img }}" width="50px">{{usern }}</h1>

    <br>所有問答


<h1><img src="{{ img }}" width="50px">{{usern }}</h1>
    <br>所有評論


          <li class="list-group-item" style="width: 800px"> 用戶:{{ usern }}</li>
          <li class="list-group-item" style="width: 800px"> 編號:{{ id }}</li>
          <li class="list-group-item" style="width: 800px"> 問答數:{{ ques|length }}</li>
          <li class="list-group-item" style="width: 800px"> 評論數:{{ comment|length }}</li>
複製代碼

 

4.頁面顯示相應數據:發佈的所有問答、發佈的所有評論、我的信息

效果以下:

 

5.各個頁面連接到我的中心

導航欄的暱稱鏈接:

複製代碼
 {% if username %}

        <li><a href="{{ url_for('person',user_id=user.id) }}"><h2>{{ username }}</h2></a></li>
        <li><a href="{{ url_for('logout') }}"><h2>註銷</h2></a></li>
    {% else %}
        <li><a href="{{ url_for('login') }}"><h2>登陸</h2></a></li>
        <li><a href="{{ url_for('zhuce') }}"><h2>註冊</h2></a></li>
    {% endif %}
    <li><a href="{{ url_for('question') }}"><h2>問答</h2></a></li>
</ul>
複製代碼

主頁暱稱鏈接:

  <a href="{{ url_for('person',user_id=foo.author.id) }}" target="_blank">{{ foo.author.username }}</a>

評論列表裏面的暱稱鏈接:

                <a href="{{ url_for('person',user_id=qu.author.id) }}">{{ qu.author.username }}</a>

文章中做者名字鏈接:

   做者:<a href="{{ url_for('person',user_id=ques.author.id) }}">{{ ques.author.username }}</a>

 

6.新頁面user.html,用<ul ><li role="presentation"> 實現標籤頁導航。
<ul class="nav nav-tabs">
  <li role="presentation"><a href="#">Home</a></li>
  <li role="presentation"><a href="#">Profile</a></li>
  <li role="presentation"><a href="#">Messages</a></li>
</ul>

 

複製代碼
<ul class="nav nav-tabs">


    <li class="nav"  role="presentation"><a href="#"><h3>所有問答</h3></a></li>
    <li class="nav"  role="presentation"><a href="#"><h3>所有評論</h3></a></li>
    <li class="nav"  role="presentation"><a href="#"><h3>我的中心</h3></a></li>

</ul>
複製代碼

7.user.html繼承base.html。
重寫title,head,main塊.
將上述<ul>放在main塊中.
定義新的塊user。

以下:

user.html

複製代碼
{% extends 'basic.html' %}
{% block title %} 我的中心{% endblock %}

{% block aa %}
{% block user %}{% endblock %}
 </div>
{% endblock %}
複製代碼

person.html

{% extends 'user.html' %}


{% block user %}
{% endblock %}

8.我的中心—視圖函數帶標籤頁面參數tag
@app.route('/usercenter/<user_id>/<tag>')
def usercenter(user_id, tag):
   if tag == ‘1':
       return render_template('usercenter1.html', **context)

複製代碼
# 我的中心
@app.route('/person/<user_id>/<tag>',methods=['GET','POST'])
def person(user_id,tag):
    user = User.query.filter(User.id == user_id).first()

    context = {
        'img':user.image,
        'id':user_id,
        'usern':user.username,
        'ques': Question.query.filter(Question.author_id == user_id).order_by('-creat_time').all(),
        'users': Comment.query.filter(Comment.author_id == user_id).order_by('-creat_time').all(),
        'comment': user.comments,
        'user1':user
    }
    if tag=='1':
         return render_template('person.html', **context)
    elif tag=='2':
         return render_template('person2.html', **context)
    else:
         return render_template('person3.html', **context)
複製代碼

9.我的中心—導航標籤連接增長tag參數
<li role=「presentation」><a href=「{{ url_for(‘usercenter’,user_id = user.id,tag = ‘1’) }}">所有問答</a></li>

    <li class="nav" role="presentation"><a href="{{url_for('person',user_id=user1.id,tag=1)}}"><h3>所有問答</h3></a></li>
    <li class="nav" role="presentation"><a href="{{url_for('person',user_id=user1.id,tag=2)}}"><h3>所有評論</h3></a></li>
    <li class="nav" role="presentation"><a href="{{url_for('person',user_id=user1.id,tag=3)}}"><h3>我的中心</h3></a></li>

10.我的中心—有連接到我的中心頁面的url增長tag參數
u <a href="{{ url_for('usercenter',user_id = session.get('userid'), tag=1) }}">{{ session.get('user') }}</a>

複製代碼
   <a href="{{ url_for('person',user_id=qu.author.id,tag=1) }}" target="_blank">{{ qu.author.username }}</a>


   <a class="wrap-img" href="{{ url_for('person',user_id=foo.author.id,tag=1) }}" target="_blank">
 
   <a href="{{ url_for('person',user_id=foo.author.id,tag=1) }}" target="_blank">{{ foo.author.username }}</a>
複製代碼

運行結果:

 

十6、實現導航條中的搜索功能

1.準備視圖函數search()

# 查找
@app.route('/search/')
def search():
  pass

 

2.修改base.html 中搜索輸入框所在的

<form action="{{ url_for('search') }}" method="get">

   <input name="q" type="text" placeholder="請輸入關鍵字">

複製代碼
  <li>
        <form action="{{url_for('search') }}" method="get"   >
        <input class="d1" name="q" type="text" placeholder="搜索從這裏開始...">
        <button class="b" type="submit">搜索</button>
            </form>
    </li>
複製代碼

 

 

3.完成視圖函數search()

獲取搜索關鍵字
q = request.args.get('q’)

 

條件查詢
qu = Question.query.filter(Question.title.contains(q)).order_by('-creat_time’)

 

加載查詢結果:
return render_template('index.html', question=qu)

複製代碼
# 查找
@app.route('/search/')
def search():
   qu=request.args.get('q')
   ques=Question.query.filter(
      
           Question.title.contains(qu)
       ).order_by('-creat_time')
   return render_template('basic.html',questions=ques)
複製代碼

 

 

4.組合條件查詢
from sqlalchemy import or_, and_

 

複製代碼
# 查找
@app.route('/search/')
def search():
qu=request.args.get('q')
ques=Question.query.filter(
or_(
Question.title.contains(qu),Question.detail.contains(qu)
)).order_by('-creat_time')
return render_template('basic.html',questions=ques)
複製代碼

 

運行結果:

如下爲搜索「我」的結果

 

十7、密碼保護

1.更新User對象,設置對內的_password

class User(db.Model):

    __tablename__ = 'user' 

    _password = db.Column(db.String(200), nullable=False) #內部使用

 

代碼以下:

複製代碼
class User(db.Model):
    __tablename__ = 'user'
    # 創建一個表user
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200),nullable=False)
    image = db.Column(db.String(100))
    say = db.Column(db.String(50))
複製代碼

 

2.編寫對外的password

from werkzeug.security import generate_password_hash, check_password_hash

    @property

    def password(self):  #外部使用,取值

        return self._password

    @password.setter

    def password(self, row_password):#外部使用,賦值

        self._password = generate_password_hash(row_password)

 

代碼以下:

複製代碼
   @property
    def password(self):#外部使用
        return self._password

    @password.setter
    def password(self,row_password):
        self._password=generate_password_hash(row_password)
複製代碼

 

3.密碼驗證方法:

    def check_password(self, row_password): #密碼驗證

        result = check_password_hash(self._password,row_password)

        return result

 

代碼以下:

    def check_password(self,row_password):
        result=check_password_hash(self._password,row_password)
        return result

 

 

4.登陸驗證:

        password1 = request.form.get('password')

        user = User.query.filter(User.username == username).first()

        if user:

            if user.check_password(password1):

 

代碼以下:

複製代碼
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    else:
        usern=request.form.get('username')
        passw=request.form.get('password')
        user=User.query.filter(User.username==usern).first()
        #判斷用戶名是否存在
        if user:

            # if user.password==passw:
            if user.check_password(passw):
                session['user'] = usern#字典鍵值
                session['userid'] = user.id
                session.permanent = True
                return redirect(url_for('index'))
            else:
                return u' password error'
        else:
            return u' username  not existed'
複製代碼

運行結果:

 

 

 

十8、模型分離

1.新建models.py,將模型定義所有放到這個獨立的文件中。

models.py

複製代碼
from werkzeug.security import generate_password_hash,check_password_hash
from datetime import datetime
from exts import db



class User(db.Model):
    __tablename__ = 'user'
    # 創建一個表user
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200),nullable=False)
    image = db.Column(db.String(100))
    say = db.Column(db.String(50))
   
    @property
    def password(self):#外部使用
        return self._password

    @password.setter
    def password(self,row_password):
        self._password=generate_password_hash(row_password)

    def check_password(self,row_password):
        result=check_password_hash(self._password,row_password)
        return result
#db.create_all()
# 創建一表question
class Question(db.Model):
    __tablename__ = 'question'

    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'))
    author=db.relationship('User',backref=db.backref('question'))
    classify=db.Column(db.Enum('散文拾貝', '心靈雞湯','笑談風聲', '爲所欲爲'),nullable=False)
    click = db.Column(db.INT, default=0)


# db.create_all()



# class Log(db.Model):
#     __tablename__ = 'log'
#     # 創建一個表log
#     id = db.Column(db.Integer,primary_key=True,autoincrement=True)
#     username = db.Column(db.String(20),nullable=False)
#     password = db.Column(db.String(20),nullable=False)


#db.create_all()
複製代碼

2.新建exts.py,將db = SQLAlchemy()的定義放到這個獨立的文件中。

exts.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

3.models.py和主py文件,都從exts.py中導入db。

from exts import db

 

4.在主py文件中,對db進行始化,db.init_app(app)。

主py

複製代碼
from flask import Flask
from flask import render_template,request,redirect,url_for,session
import config
from sqlalchemy import  or_ ,and_
from functools import wraps
from models import Question,User,Comment
from exts import db
app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
複製代碼

 

十9、數據遷移

1.pip install flask-migrate  #Flask-Migrate 是一個數據遷移框架,須要經過Flask-script庫來操做.

2. pip install flask-script  #經過命令行來操做Flask

 

3. 新建模型更改文件:manage.py

 

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from myqa import app
from exts import db

from models import Question, 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() #啓動Manger實例接收命令行中的命令。
複製代碼
from flask_script import Manager
from flask_migrate import Migrate,MigrateCommand
from untitled6 import  app
from  exts import  db

from  models import  User,Question,Comment

manager=Manager(app)#mangager只有一個參數:一個Flask實例

migrate=Migrate(app,db)#使用Migrate綁定app和db

#添加遷移腳本命令
manager.add_command('db',MigrateCommand)#加入命令,命令行輸入python manage.py db migrate


if __name__ == '__main__':
    manager.run()#啓動Manger實例接收命令行中的命令
複製代碼

 

4. 要models.py發生改變後,在cmd命令行,進到manage.py所在的路徑,執行:

(1)初始化遷移環境,只運行一次
python manage.py db init

 

(2)生成遷移文件,模型改變了就須要執行
python manage.py db migrate

 

 

(3)映射到數據庫表中
python manage.py db upgrade

 

字段修改語句:

複製代碼
class User(db.Model):
    __tablename__ = 'user'
    # 創建一個表user
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    username = db.Column(db.String(20),nullable=False)
    _password = db.Column(db.String(200),nullable=False)
    image = db.Column(db.String(100))
    say = db.Column(db.String(50))
#加入該字段測試,試完刪除 a=db.Column(db.String(50))
複製代碼

 

數據庫修改結果:

數據遷移生成文件及該flask框架整理佈局:

 

二10、淺談flask框架及其應用

爲了理解 Flask 框架是如何抽象出Web開發中的共同部分,咱們先來看看Web應用程序的通常流程。對於Web應用來講,當客戶端想要獲取動態資源時,就會發起一個HTTP請求(好比用瀏覽器訪問一個 URL),Web應用程序會在後臺進行相應的業務處理,(從數據庫或者進行一些計算操做等)取出用戶須要的數據,生成相應的HTTP響應(固然,若是訪問靜態資源,則直接返回資源便可,不須要進行業務處理)。整個處理過程以下圖所示:

實際應用中,不一樣的請求可能會調用相同的處理邏輯。這裏有着相同業務處理邏輯的 HTTP 請求能夠用一類 URL 來標識。好比論壇站點中,對於全部的獲取Topic內容的請求而言,能夠用 topic/&lt;topic_id&gt;/ 這類URL來表示,這裏的 topic_id 用以區分不一樣的topic。接着在後臺定義一個 get_topic(topic_id) 的函數,用來獲取topic相應的數據,此外還須要創建URL和函數之間的一一對應關係。這就是Web開發中所謂的路由分發,以下圖所示:

寫在最後:

此文章僅限flask框架的基本使用,要想學好這個框架,有必定的頁面製做基礎和python基礎是不夠的,還須要掌握請求-響應循環、請求調度、請求Hooks、Flask擴展等等網絡技術,不然也只是小試牛刀,但願這篇文章可以給初學者提供必定的幫助。

相關文章
相關標籤/搜索