上一章实现了登录的部分功能,之所以说是部分功能,是因为用户名和密码写成固定值肯定是不可以的,一个整体的功能,至少需要注册,登录,密码修改等,这就需要提供一个把这些值存储到数据库的能力。

当前的主流数据库分为两种,即关系数据库和NoSql数据库,对于中小型的系统来说,两种数据库性能,易用性都相当,都是很好的选择。

基础配置

这里使用SQLAlchemy数据库框架的flask集成包,即flask-SQLAlchemy来进行数据库操作。

SQLAlchemy是一个非常好的框架,简化了数据库的操作,即提供了高层次的ORM,也提供了低层次的SQL功能,使用起来非常方便。

安装方式与之前类型,还是pip命令:

pip3.6 install flask-sqlalchemy

安装完成之后,对default的配置部分进行修改,首先导入包:

from flask.ext.sqlalchemy import SQLAlchemy

然后配置链接字符串:

app.config["SQLALCHEMY_DATABASE_URI"]='mysql://root:1234@localhost/cblog'

配置请求结束后更改自动提交:

app.config["SQLALCHEMY_COMMIT_ON_TEARDOWN"]=True

实例化SQLAlchemy:

db=SQLAlchemy(app)

模型设置

安装完成之后,继续完善登录的例子,修改default.py文件,新增User模型(类)和Role模型(以示关联)

Role类

class Role(db.Model):       #需继承模型
__tablename__="roles" #db中表明,如果不设置,则会与class同的默认名
id=db.Column(db.Integer,primary_key=True) #SQLAlchemy要求必须有主键,一般命名为id即可
name=db.Column(db.String(50),unique=True) #表示name为字符串,不重复
users=db.relationship("User",backref='role') #关联user模型,并在user中添加反向引用(backref)

User类

class User(db.Model):
__tablename__="users"
id=db.Column(db.Integer,primary_key=True)
username=db.Column(db.String(50),unique=True,index=True) #此列带索引
password=db.Column(db.String(50))
role_id=db.Column(db.Integer,db.ForeignKey("roles.id")) #外键指向roles表中的id列

下面要考虑如何执行,要既方便,有不能入侵到逻辑代码,这就要求不能硬编码到逻辑代码中,比如把判断db状态的代码作为参数传递给app.run(),这时候shell就派上了用场

配置脚本

想让flask支持命令行脚本,首先需要安装flask-script扩展:

pip3.6 install flask-script

修改default.py的代码:

from flask.ext.script import Manager

mamager=Manager(app)

....

if __name__=='__main__':
#app.run(debug=True)
mamager.run()

修改过之后,再次运行:

python default.py

发现并没有成功运行,而是有提示:

可以看到,后边需要参数,分别为shell(执行脚本),runserver(启动服务)和帮助

下边启动服务:

python default.py runserver

服务成功执行

数据库更多配置

但这个时候,访问站点(127.0.0.1:5000),会出现500错误,提示没有mysql模块,这是为什么呢?很明显是没有安装mysql驱动的原因,使用pip命令安装驱动:

pip3.6 install MySQL-python

发现出现错误,显示内容为(此处仅为win系统):

根据提示,安装c++的工具包,按照提示上的下载地址

http://landinghub.visualstudio.com/visual-cpp-build-tools

下载完成直接为exe文件,安装

重启后安装MySQL-python,发现还是不可以,经百度后才发现,MySQLdb这个库最高只支持到python2.7,不在支持3.x,那只好用其他办法,使用PyMySQL库:

pip3.6 install PyMySQL

然后修改default.py的代码,增加两行:

import pymysql
pymysql.install_as_MySQLdb()

进入源码,注意这一行:

sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"]

即可成功使用并连接mysql。
浏览器输入连接,正确进入站点。

接下来,使用shell建立数据库表,进入default.py根目录:

python default.py shell
from default import db
db.create_all()

这时候如果没有报错,那么数据库表应该建立完成:

数据库迁移

那么问题来了,这时候,对模型进行修改,是不会反应到db中的,那么如果修改怎么办呢?对于当前来说,也很简单:

db.drop_all()
db.create_all()

但这个仅仅是现在调试时候使用,如果db中已经有了数据,则这个肯定是无法忍受的,这时候,就轮到数据库迁移插件Migrate登场了,首先还是一样,需要进行安装:

pip3.6 install flask-migrate

和之前一样,安装完之后修改default.py文件进行配置:

from flask.ext.migrate import Migrate,MigrateCommand

migrate=Migrate(app,db) #配置迁移
mamager.add_command("db",MigrateCommand) #配置迁移命令

然后使用init命令初始化迁移仓库

 python default.py db init

命令行显示:

然后增加migrations目录:

表示迁移文件已经初始化完成。

migrate框架提供了一些命令来进行迁移操作,分别为(使用default.py文件举例):

#根据差异创建迁移
python default.py db migrate -m "说明"
#改动差异
python default.py db upgrade
#取消差异改动
python default.py db downgrade

回到表单

接下来看看登录如何与数据库关联起来,修改login方法内的代码:

@app.route("/login",methods=["POST"])
def loginPost():
username=request.form.get("username","")
password=request.form.get("password","")
user=User.query.filter_by(username=username,password=password).first() #数据库查询
if user is not None:
session["user"]=username
return render_template("/index.html",name=username,site_name='myblog')
else:
flash("您输入的用户名或密码错误")
return render_template("/login.html") #返回的仍为登录页

执行结果非常完美。

一些总结

下面是一些关于python和db相连的总结性的东西

数据类型

db类型(SQLAlchemy) python类型
Integer int
SmallInteger int
BigInteger long
Float float
Numeric decimal.Decimal
String str
Text str
Boolean bool
Date datetime.date
Time datetime.time
DateTime datetime.datetime
PickleType python对象序列化
LargeBinary str(二进制)

列选项

primary_key True为主键(每个对象至少一列)
unique True为不允许重复
index True为创建索引
nullable True为可为空,false为不许为空
default 设置默认值
backref 为另一模型添加反向引用
primaryjoin 明确两个模型直接的链接条件
lazy 可选值:select:首次访问时加载,immediate:源对象加载后立即加载,joined使用联结立即加载,subquery:使用子查询立即加载,noload:永不加载,dynamic:不加载记录,但提供加载的查询
uselist 如果为false,则不使用列表,而使用用标量值
order_by 排序方式
secondary 多对多时指定关系表的名字
secondaryjoin 手动设置多对多关系中二级联结条件

数据库操作

db.session.add(model) 插入或修改记录(需commit)
db.session.delete(model) 删除记录(需commit)
model.query 查询记录

查询过滤器

all() 返回全部记录
filter() 将过滤器添加至原查询,返回新结果
filter_by() 将等值过滤器添加至原查询,返回新结果
limit() 限制结果数量,分页用
offset() 偏移结果,分页用
order_by() 排序
group_by() 分组
first() 返回首结果,没有则返回None
first_or_404() 返回首结果,没有则返回404响应
get() 返回主键对应的记录,没有则返回None
get_or_404() 返回主键对应的记录,没有则返回404响应
count() 返回全部数量
paginate() 返回Paginate对象,它包含指定范围内的结果  

经过这几章,登录功能已经基本完成,在下一章中将讲解用户注册的相关功能。

一个web应用的诞生(4)的更多相关文章

  1. 一个web应用的诞生(1)--初识flask

    基于flask的web应用的诞生 Flask是一个非常优秀的web框架,它最大的特点就是保持一个简单而易于扩展的小核心,其他的都有用户自己掌握,并且方便替换,甚至,你可以在社区看到众多开源的,可直接用 ...

  2. 一个web应用的诞生--使用模板

    经过了第一章的内容,已经可以做出一些简单的页面,首先用这种方式做一个登录页面,首先要创建一个login的路由方法: @app.route("/login",methods=[&qu ...

  3. 一个web应用的诞生--美化一下

    经过上一章的内容,其实就页面层来说已结可以很轻松的实现功能了,但是很明显美观上还有很大的欠缺,现在有一些很好的前端css框架,如AmazeUI,腾讯的WeUI等等,这里推荐一个和flask集成很好的b ...

  4. 一个web应用的诞生--数据存储

    上一章实现了登录的部分功能,之所以说是部分功能,是因为用户名和密码写成固定值肯定是不可以的,一个整体的功能,至少需要注册,登录,密码修改等,这就需要提供一个把这些值存储到数据库的能力. 当前的主流数据 ...

  5. 一个web应用的诞生--数据表单

    下面把角色分为两种,普通用户和管理员用户,至少对于普通用户来说,直接修改DB是不可取的,要有用户注册的功能,下面就开始进行用户注册的开发. 用户表 首先要想好用户注册的时候需要提供什么信息:用户名.密 ...

  6. 一个web应用的诞生(6)--用户账户

    之前登录注册的功能都已经完成,但是登录成功回到首页发现还是白茫茫的一片,对的,title一直都写得博客,那么最终目的也是写出一个轻博客来,但是,在发表文章之前是不是要先记录一下登录状态呢? 用户登录 ...

  7. 一个web应用的诞生(7)--结构调整

    现在所有的Py代码均写在default.py文件中,很明显这种方法下,一旦程序变的负责,那么无论对于开发和维护来说,都会带来很多问题. Flask框架并不强制要求项目使用特定的组织结构,所以这里使用的 ...

  8. 一个web应用的诞生(8)--博文发布

    这个系统一直号称轻博客,但貌似博客的功能还没有实现,这一章将简单的实现一个博客功能,首先,当然是为数据库创建一个博文表(models\post.py): from .. import db from ...

  9. 一个web应用的诞生(9)--回到用户

    在开始之前,我们首先根据之前的内容想象一个场景,用户张三在网上浏览,看到了这个轻博客,发现了感兴趣的内容,于是想要为大家分享一下心情,恩?发现需要注册,好,输入用户名,密码,邮箱,并上传头像后,就可以 ...

  10. 一个web应用的诞生(10)--关注好友

    下面回到首页中,使用一个账户登录,你肯定已经注意到了这里的内容: 没错,现在都是写死的一些固定信息,其中分享数量很容易就可以获取,只需要修改首页模板: <p class="text-m ...

随机推荐

  1. rocketmq的一些内容

    分布式开放消息系统(RocketMQ)的原理与实践 作者 CHEN川 关注 2016.02.25 15:43* 字数 6784 阅读 122302评论 41喜欢 321赞赏 7 一年前为了一次内部分享 ...

  2. java:LeakFilling(Spring)

    1.配置文件总结: bean节点: id:用户自定义名称,用于标识当前对象,可以通过getBean(String id)从容器中获取该对象. class:要交给spring容器创建的对象的全类名(包名 ...

  3. Platform区分不同平台

    用于区分平台 OS 属性 表示当前的平台类型.只有 ios 与 android 两个值.如可以使用为同一个属性在不同的平台上赋不同的值 const styles = StyleSheet.create ...

  4. layer最大话.最小化.还原回调方法

    layer.open({              type: 1,             title: ‘在线调试‘,           content: ‘这里是内容‘,            ...

  5. 公共子序列_NOI导刊2011提高(03)题

    题面 这道题有点坑人啊~ 首先,它需要取模,模数是100000000:(窝在这里死了好久好久,看了别人的代码才发现这一点) 然后我发现题解中没有序列自动机的方法,于是就来一发 首先,虽然序列自动机在定 ...

  6. [BJWC2008] Gate Of Babylon

    题目链接 容斥+隔板法+Lucas定理 #include <bits/stdc++.h> using namespace std; const int N=1e5+10; int n,m, ...

  7. 修建泳池&最大子矩阵

    [题目描述] 夏天到了,学校打算在教学楼后面的空地上挖一个泳池供大家使用. 经过实地勘察,这块土地可以划分成N 行M 列的方格,有的方格是树,有的方格是空地.现在要找一块最大的矩形空地修建泳池,请问泳 ...

  8. 洛谷 P3388 【模板】割点(割顶)(Tarjan)

    题目链接 https://www.luogu.org/problemnew/show/P3388 模板题 解题思路 什么是割点? 怎样求割点? dfn :即时间戳,一张图的dfs序(dfs遍历时出现的 ...

  9. Laravel 程序优化

    转载: Laravel 程序优化 说明 作为优秀的开发者,在日常编码中,应积极培养书写高执行效率代码的意识.不过项目运行效率是一个系统性工程,不应该只停留在代码层面上,有时更应该考虑整个项目架构,包括 ...

  10. 初识MySQL <一>

    创建一个 表 create table student( id int(10) not null unique auto_increment primary key, name varchar(30) ...