×

Flask学习记录之Flask-SQLAlchemy

穆琪 穆琪 发表于2018-08-23 23:08:28 浏览414 评论0

抢沙发发表评论

Flask-SQLAlchemy库让flask更方便的使用SQLALchemy,是一个强大的关系形数据库框架,既可以使用orm方式操作数据库,也可以使用原始的SQL命令. Flask-Migrate 是一个数据迁移框架,需要通过Flask-script库来操作.  

一.配置Flask-SQLAlchemy

程序使用的数据库地址需要配置在SQLALCHEMY_DATABASE_URI中,SQLALchemy支持多种数据库,配置格式如下: Postgres:
  postgresql://scott:tiger@localhost/mydatabase
MySQL:
  mysql://scott:tiger@localhost/mydatabase
Oracle:
  oracle://scott:tiger@127.0.0.1:1521/sidname
SQLite:
  sqlite:////absolute/path/to/foo.db
db是SQLALchemy类的实例,表示程序使用的数据库,为用户提供Flask-SQLALchemy的所有功能
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
#配置数据库地址
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
#该配置为True,则每次请求结束都会自动commit数据库的变动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)
#也可以db = SQLAlchemy()        db.init_app(app)

二.定义模型

Flask-SQLALchemy使用继承至db.Model的类来定义模型,如:
class User(db.Model, UserMixin):#UserMixin是Flask-Login库中所需要的
    __tablename__ = 'users'
    #每个属性定义一个字段
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))
def __repr__(self):
        return '<User %r>' % self.username
定义完需要在Python Shell中导入db,调用db.create_all()来创建数据库 (1)常用字段选项: primary_key 设置主键 unique 是否唯一 index 是否创建索引 nullable 是否允许为空 default 设置默认值,可以传入函数的引用 如传入 datetime.datetime.utcnow 则每次创建时时间都是最新时间

三.增删查改

(1) 插入数据:
from app.models import User
from app import db

#创建一个新用户
u = User()
u.username = 'abc'
u.password = 'abc'
#将用户添加到数据库会话中
db.session.add(u)
#将数据库会话中的变动提交到数据库中,如果不Commit,数据库中是没有改动的
db.commit()
(2)查找数据:
#返回所有用户保存到list中
user_list = User.query.all()

#查找username为abc的第一个用户,返回用户实例
u = User.query.filter_by(username='abc').first()

#模糊查找用户名以c结尾的所有用户
user_list  = User.query.filter(username.endswith('c')).all()

#查找用户名不是abc的用户
u = User.query.filter(username != 'abc').first()
(3)删除数据:
user = User.query.first()
db.session.delete(user)
db.session.commit()
(4)修改数据:
u = User.query.first()
u.username = 'sb'
db.session.commit()

四.一对多关系

我的理解是:在多的一边定义外键,而relathonship()函数是用来建立关系的,可以只在一边定义,也可以两边都使用(只在一边使用时加上了backref选项等同于两边都使用)
class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    #backref将在Address表中创建个名为persons的Person引用,之后可以使用address.persons访问这个地址的所有人
    addresses = db.relationship('Address', backref='persons',
                                lazy='dynamic')

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    #在多的一边使用db.ForeignKey声明外键
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

五.多对多关系

多对多关系可以分解为原表和关联表之间两个多对一关系,如下代码建立了学生与所选课程之间的关系:
#创建关联表,两个字段的外键是另两个表,一个学生对应多个关联表,一个关联表对应多个课程
registrations = db.Table('registrations',
                         db.Column('student_id',db.Integer,db.ForeignKey('students.id')),
                         db.Column('class_id',db.Integer,db.ForeignKey('classes.id'))
                         )

class Student(db.Model):
    __tablename__ = 'students'
    id = db.Column(db.Integer,primary_key=True,)
    name = db.Column(db.String)
    classes = db.relationship('Class',
                              secondary = registrations, #关联表,只需要在一个表建立关系,sqlalchemy会负责处理好另一个表
                              backref = db.backref('students',lazy='dynamic'),
                              lazy = 'dynamic')


class Class(db.Model):
    __tablename__ = 'classes'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
多对多的使用:
#学生1增加一门选课
student1.classes.append(class1)
#学生1退选class1
student1.classes.remove(class1)
#学生1所选课程,由于指定了lazy='dynamic'所以没有直接返回列表,而需要使用.all()
student1.classes.all()

六.分页导航

Flask-SQLALchemy的Pagination对象可以方便的进行分页, 对一个查询对象调用pagenate(page, per_page=20, error_out=True)函数可以得到pagination对象,第一个参数表示当前页,第二个参数代表每页显示的数量,error_out=True的情况下如果指定页没有内容将出现404错误,否则返回空的列表
#从get方法中取得页码
page = request.args.get('page', 1, type = int)
#获取pagination对象
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=10, error_out = False)

#pagination对象的items方法返回当前页的内容列表
    posts = pagination.items

pagination对象常用方法:

has_next :是否还有下一页 has_prev :是否还有上一页 items : 返回当前页的所有内容 next(error_out=False) : 返回下一页的Pagination对象 prev(error_out=False) : 返回上一页的Pagination对象 page : 当前页的页码(从1开始) pages : 总页数 per_page : 每页显示的数量 prev_num : 上一页页码数 next_num :下一页页码数 query :返回 创建这个Pagination对象的查询对象 total :查询返回的记录总数 iter_pages(left_edge=2, left_current=2, right_current=5, right_edge=2)

在模版中使用

{% macro render_pagination(pagination, endpoint) %}
  <div class=pagination>
  {%- for page in pagination.iter_pages() %}
    {% if page %}
      {% if page != pagination.page %}
        <a href="{{ url_for(endpoint, page=page) }}">{{ page }}</a>
      {% else %}
        <strong>{{ page }}</strong>
      {% endif %}
    {% else %}
      <span class=ellipsis>…</span>
    {% endif %}
  {%- endfor %}
  </div>
{% endmacro %}