一、个人学期总结
本人在一学期时间内学习并实现基于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是新增的属性