Python---Flask--04--SQLAlchemy

大多数的数据库引擎都有对应的 Python 包,包括开源包和商业包。Flask 并不限制你使用何种类型的数据库包,因此可以根据自己的喜好选择使用 MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。

如果这些都无法满足需求,还有一些数据库抽象层代码包供选择,例如 SQLAlchemy 和MongoEngine。你可以使用这些抽象包直接处理高等级的 Python 对象,而不用处理如表、文档或查询语言此类的数据库实体。

使用Flask-SQLAlchemy管理数据库

安装

pip install flask-sqlalchemy

基本使用

FLask-SQLAlchemy数据库URL

数据库引擎 URL
MySQL mysql://username:password@hostname/database
Postgres postgresql://username:password@hostname/database
SQLite(Unix) sqlite:////absolute/path/to/database
SQLite(Windows) sqlite:///c:/absolute/path/to/database

配置

from flask.ext.sqlalchemy import SQLAlchemy
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =
 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)

db 对象是 SQLAlchemy 类的实例,表示程序使用的数据库,同时还获得了 Flask-SQLAlchemy提供的所有功能。

定义模型

from app import db
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin


class User(db.Model, UserMixin):
    __tablename = 'user'  #表名称

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    add_time = db.Column(db.DateTime, default=datetime.now)
    state = db.Column(db.Integer, default=1, comment='状态 1--有效 0--无效')

    def __repr__(self):
        return '<User %r>'% self.username
    # @property
    # def password(self):
    #     raise AttributeError('password not read')
    #
    # @password.setter
    # def password(self,password):
    #     self.password = generate_password_hash(password)


    def verify_password(self,pwd):
        """验证密码是否正确"""
        return check_password_hash(self.password, pwd)

类变量 tablename 定义在数据库中使用的表名。如果没有定义 tablename,Flask-SQLAlchemy 会使用一个默认名字,但默认的表名没有遵守使用复数形式进行命名的约定,所以最好由我们自己来指定表名。其余的类变量都是该模型的属性,被定义为 db.Column类的实例。
db.Column 类构造函数的第一个参数是数据库列和模型属性的类型。列出了一些可用的列类型以及在模型中使用的 Python 类型。

类型 Python中的类型 说明
Integer Int 整形
SmallInteger int 短整型
BigInteger ing或者long 不限长度
Float float 浮点型
Numeric decimal 定点数
String str 字符串
Text str 文本
DateTime datetime.datetime 日期和时间
Date datetime.date 日期
Time datetime.time 时间
Boolean bool 布尔
Enum str 枚举
Interval datetime.timedelta 时间间隔

db.Column中其余参数指定属性的配置选项:

选项名 说明
primary_key 如果设置为True,则是主键
unique 如果设置为True,这列不允许出现重复
index 如果设置为True,为这列创建索引,提示查询效率
nullable 如果设置为True, 这列允许使用空值,如果设为Fasle,这列不允许使用空值
default 为这列设置默认值

关系

关系型数据库使用关系把不同表中的行联系起来。表示用户和角色之间的一种简单关系。这是角色到用户的一对多关系,因为一个角色可属于多个用户,而每个用户都只能有一个角色。
一对多关系在模型类中的表示方法如示例所示:

class Role(db.Model):
 # ...
    users = db.relationship('User', backref='role')

class User(db.Model):
 # ...
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

关系使用 users 表中的外键连接了两行。添加到 User 模型中的 role_id 列被定义为外键,就是这个外键建立起了关系。传给 db.ForeignKey() 的参数 'roles.id' 表明,这列的值是 roles 表中行的 id 值。

添加到 Role 模型中的 users 属性代表这个关系的面向对象视角。对于一个 Role 类的实例, users 属性将返回与角色相关联的用户组成的列表。db.relationship() 的第一个参数表明这个关系的另一端是哪个模型。如果模型类尚未定义,可使用字符串形式指定。

db.relationship() 中的 backref 参数向 User 模型中添加一个 role 属性,从而定义反向关系。这一属性可替代 role_id 访问 Role 模型,此时获取的是模型对象,而不是外键的值。

大多数情况下,db.relationship() 都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。例如,如果 User 模型中有两个或以上的列定义为 Role 模型的外键,SQLAlchemy 就不知道该使用哪列。如果无法决定外键,你就要为 db.relationship() 提供额外参数,从而确定所用外键。表 列出了定义关系时常用的配置选项。
表 常用的SQLAlchemy关系选项

选项名 说  明
backref 在关系的另一个模型中添加反向引用
primaryjoin 明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定
lazy 指定如何加载相关记录。可选值有 select(首次访问时按需加载)、immediate(源对象加
载后就加载)、joined(加载记录,但使用联结)、subquery(立即加载,但使用子查询),
noload(永不加载)和 dynamic(不加载记录,但提供加载记录的查询)
uselist 如果设为 Fales,不使用列表,而使用标量值
order_by 指定关系中记录的排序方式
secondary 指定多对多关系中关系表的名字
secondaryjoin SQLAlchemy 无法自行决定时,指定多对多关系中的二级联结条件

除了一对多之外,还有几种其他的关系类型。一对一关系可以用前面介绍的一对多关系表示,但调用 db.relationship() 时要把 uselist 设为 False,把“多”变成“一”。多对一关系也可使用一对多表示,对调两个表即可,或者把外键和 db.relationship() 都放在“多”这一侧。最复杂的关系类型是多对多,需要用到第三张表,这个表称为关系表。

数据库操作

添加

import db
user = User(username='',password='')
db.session.add(iser)
dn.session.commit()

更新

import db
user = User.query.get(id)
user.name='aaaaaaa'
db.session.commit()

删除

import db
user.User.query.get(id)
db.session.delete(user)
db.session.commit()

查询

query.all() 获取全部
query.filter() 把过滤器添加到原查询上,返回一个新的查询
filter_by() 把等值过滤器添加到原查询上,返回一个新的查询
limit() 使用指定的值限制返回的结果数量,返回一个新的查询
offset() 偏移原查询返回的结果,返回一个新的结果
order_by 根据指定条件对原查询结果进行排序,返回一个新查询
group_by 根据指定条件对原查询结果进行分组,返回一个新的查询
first() 返回查询的第一个结果,如果没有返回None
first_or_404() 返回查询的第一个结果,如果没有结果返回404错误
get() 返回指定主键对应的行,如果没有返回None
get_or_404() 返回指定主键对应的行,如果没有找到对象,则终止请求,返回404错误
count() 返回查询结果的数量
paginate() 返回一个Paginage对象,它包含指定范围的结果

在视图函数中操作数据库

@home.route('/register', methods=['GET', 'POST'])
def register():
    """注册"""
    form = RegisterForm()

    if form.validate_on_submit():
        data = form.data

        user = User(
            username=data['username'],
            password=generate_password_hash(data['password']),
            email=data['email']
        )
        db.session.add(user)
        db.session.commit()
        flash('注册成功')
        return redirect(url_for('home.login'))

    return render_template('/home/user/register.html', form=form)
僵尸将臣
原文地址:https://www.cnblogs.com/sunshenggang/p/11066099.html