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

当前的主流数据库分为两种,即关系数据库和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应用的诞生(5)--数据表单

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

  2. Node.js 从零开发 web server博客项目[数据存储]

    web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...

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

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

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

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

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

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

  6. 渐进式web应用开发---ajax本地数据存储(四)

    在前几篇文章中,我们使用service worker一步步优化了我们的页面,现在我们学习使用我们之前的indexedDB, 来缓存我们的ajax请求,第一次访问页面的时候,我们请求ajax,当我们继续 ...

  7. 一个web应用的诞生(4)

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

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

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

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

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

随机推荐

  1. Kali-linux控制Meterpreter

    Meterpreter是Metasploit框架中的一个杀手锏,通常作为利用漏洞后的攻击载荷所使用,攻击载荷在触发漏洞后能够返回给用户一个控制通道.当使用Armitage.MSFCLI或MSFCONS ...

  2. Eclipse配置多个Tomcat服务器

    我们在开发大型web项目时,经常需要在eclipse中同时启动多个tomcat服务器来开启多个服务.这里讲解一下如何在eclipse中配置多个tomcat服务器. 配置步骤 1. 在tomcat官网( ...

  3. 用PSCP在Windows和Linux之间相互传输文件

    在Linux服务器之间相互传文件我们常用 scp命令,但是在Linux和Windows之间相互传输就不那么直接了. 使用 Putty的 PSCP 则会简单的多 1. 下载 http://www.chi ...

  4. vlc源码分析(三) 调用live555接收RTSP数据

    首先了解RTSP/RTP/RTCP相关概念,尤其是了解RTP协议:RTP与RTCP协议介绍(转载). vlc使用模块加载机制调用live555,调用live555的文件是live555.cpp. 一. ...

  5. Gradle Goodness: Group Similar Tasks

    In Gradle we can assign a task to a group. Gradle uses the group for example in the output of $ grad ...

  6. Notes 20180312 : String第四讲_String上的操作

    作为一个基本的工具类,同时又是使用频率很高的类,Java为其提供了丰富的方法支持.Java中的String类中包含了50多个方法.最令人惊讶的是绝大多数方法都很有用,下面我们根据功能来分类介绍一下: ...

  7. Oracle高级函数篇之递归查询start with connect by prior简单用法

    路飞:" 把原来CSDN的博客转移到博客园咯!" 前段时间,自己负责的任务中刚好涉及到了组织关系的业务需求,自己用了oracle递归查询.下面简单来举个例子.在工作中我们经常会遇到 ...

  8. angular setInterval计时操作

    在angular中setInterval方法是单向绑定,只绑定一次,无法实现计时效果, 可以使用$interval实现.附上代码:

  9. 偏前端-HTML5 sessionStorage-会话存储

    sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.本篇主要介绍 sessionStorage(会话存储) ...

  10. 偏前端 + rsa加解密 + jsencrypt.min.js--(新增超长字符分段加解密)

    <html> <head> <title>JavaScript RSA Encryption</title> <meta charset=&quo ...