一、前言(個人學期總結)
個人總結一下這學期對於Python+Flask+MysqL的web建設技術過程的學習體會,Flask小辣椒框架相對於其他框架而言,更加穩定,不會有莫名其妙的錯誤,容錯性強,運行效果好,報錯信息明了, Python是近幾年流行起來的語言,簡單易懂,很好上手,強大的庫讓我們可以站在巨人的肩膀上寫代碼,應證了人們常說的那句“人生苦短,我用python”,MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 是最流行的關系型數據庫管理系統之一,基本功能都能准確無誤的給予數據支持。在本次建站過程中,前端界面采用的是html、css、JavaScript,后端采用python作為支持。
從一開始接觸的是turtle庫繪制圖形,在沒有接觸基本語法的情況下,以為會因為基礎不扎實而學起來吃力,然而,turtle庫的學習,打開了我們對python的學習興趣的閘門,這是一門多么簡潔實用的語言,python的第三方庫是多么的強大,逐漸的,在對庫的使用中熟悉了python的語法,學起來一點也不吃力,有了html基礎,加上Bootstrap框架的引用,就可以制作出一個靜態頁面,再有了python基礎以及連接數據庫的知識,就可以完成web建站了。
本次的mysql運用的是遠程數據庫,便於搭建環境和數據存儲,可視化軟件是SQLyog。
二、使用工具
主要工具有:pycharm64.exe + Python 3.6 64-bit + MySQL +SQLyog(輔助工具)
Python下載地址:https://www.python.org/downloads/
MySQL下載地址:https://www.mysql.com/downloads/
Pycharm下載地址:https://www.jetbrains.com/pycharm/download/#section=windows
三、完成基本的頁面設計
①導航條
②登陸界面
③注冊界面
④發布問答界面
四、Flask & 概覽
1、初始化
在這章,你將學到Flask應用程序的不同部分。同時,你將編寫和運行你的第一個Flask web應用程序。
所有的Flask應用程序都必須創建一個 應用程序實例 。使用web服務器網關接口協議將所有從客戶端接收的請求傳遞給這個對象處理。這個應用程序實例就是Flask類的一個對象,通常使用下面的方式創建:
1
2
|
from
flask
import
Flask
app
=
Flask(__name__)
|
Flask類構造函數唯一需要的參數就是應用程序的主模塊或包。對於大多數應用程序,Python的__name__變量就是那個正確的、你需要傳遞的值。
注:對於Flask開發者來說,傳給Flask應用程序構造函數的name參數是比較容易弄混淆的。Flask使用這個參數來確定應用程序的根目錄,這樣以后可以相對這個路徑來找到資源文件。
稍后你可以看到更復雜的應用程序實例初始化,但是對於簡單應用程序這些已經足夠了。
2、路由和視圖函數
客戶端例如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同樣是字符串類型,但並不認為斜杠是分隔符,而認為它們是動態組件的一部分。
3、服務啟動
應用程序實例有一個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服務。
4、一個完整的應用程序
在上一節,你學習了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應用程序就搭建起來了。
五、加載靜態文件,父模板與其他界面的繼承
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 %}
六、數據庫連接池
數據庫工具: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()
七、通過用戶模型,對數據庫進行增刪改查
添加數據 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()
八、完成注冊功能
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文件:
-
- <form>中設置 action和method="post"
- <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>     <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文件中:
-
- from flask import request, redirect, url_for
- @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')) #重新定向到登錄頁
運行結果:
九、完成登陸功能
登錄功能完成:
1.js:設置return
同注冊,onclick函數return True時才提交表單,return False時不提交表單。
2.html:設置
- form
- 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>       <input type="radio" name="role" value="stu">student  <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>        <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:
- @app.route設置methods
- GET
- POST
- 讀取表單數據
- 查詢數據庫
- 用戶名密碼對:
- 記住用戶名
- 跳轉到首頁
- 用戶名密碼不對:
- 提示相應錯誤。
- 用戶名密碼對:
@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'
十、登錄后更新導航
1.用上下文處理器app_context_processor定義函數
- 獲取session中保存的值
- 返回字典
#判斷是否登陸,有則在導航欄顯示用戶名 @app.context_processor def mycontext(): usern=session.get('user') if usern: return {'username':usern} else: return {}
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.完成注銷功能。
- 清除session
- 跳轉
#登出,清除session @app.route('/logout') def logout(): session.clear() return redirect(url_for('index'))
十一、完成發布功能
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'))
十二、在首頁顯示問答列表
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)
十三、從首頁問答列表標題鏈接到詳情頁
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.首頁列表顯示全部問答:
- 將數據庫查詢結果傳遞到前端頁面 Question.query.all()
- 前端頁面循環顯示整個列表。
- 問答排序
@app.route('/') def index(): context={ 'questions':Question.query.order_by('-creat_time').all() } return render_template('basic.html',**context)
2.完成問答詳情頁布局:
- 包含問答的全部信息
- 評論區
- 以往評論列表顯示區。
代碼如下:
<div class="page-header"> <h3>{{ ques.title }}<br><br> <small>作者:{{ ques.author.username }}    <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'))
運行結果:
十四、實現發布評論,並顯示評論區
代碼如下:
<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 %}
運行結果:
十五、完成個人中心相關信息
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>
運行結果:
十六、實現導航條中的搜索功能
1.准備視圖函數search()
# 查找 @app.route('/search/') def search(): p