Python_Flask系列_2.模型 Model

系列文章目录


前言

Flask-SQLAlchemy是Flask扩展,它将对SQLAlchemy的支持添加到Flask应用程序中。

一、准备

使用Flask-SQLAlchemy扩展操作数据库,首先需要建立数据库连接。数据库连接通过URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URI键中。

1.连接

pip install flask-sqlalchemy
pip install flask-mysqldb
pip install pymysql -i https://pypi.tuna.tsinghua.
edu.cn/simple

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:mysql@127.0.0.1:3306/falsk'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True

2.常用的SQLAlchemy字段类型

类型名python中类型说明
Integerint普通整数,一般是32位
SmallIntegerint取值范围小的整数,一般是16位
BigIntegerint或long不限制精度的整数
Floatfloat浮点数
Numericdecimal.Decimal普通整数,一般是32位
Stringstr变长字符串
Textstr变长字符串,对较长或不限长度的字符串做了优化
Unicodeunicode变长Unicode字符串
UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
Booleanbool布尔值
Datedatetime.date时间
Timedatetime.datetime日期和时间
LargeBinarystr二进制文件

参数

选项名说明
primary_key如果为True,代表表的主键
unique如果为True,代表这列不允许出现重复的值
index如果为True,为这列创建索引,提高查询效率
nullable如果为True,允许有空值,如果为False,不允许有空值
default为这列定义默认值
backref在关系的另一模型中添加反向引用
primary join明确指定两个模型之间使用的联结条件
uselist如果为False,不使用列表,而使用标量值
order_by指定关系中记录的排序方式
secondary指定多对多中记录的排序方式
secondary join在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件

二、数据库基本操作

1.基本概念

  • 在Flask-SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理。
    会话用db.session表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 commit() 方法提交会话。

  • 在Flask-SQLAlchemy中,查询操作是通过query对象操作数据。
    最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。

db.session.add(role)    添加到数据库的session中
db.session.add_all([user1, user2]) 添加多个信息到session中
db.session.commit()     提交数据库的修改(包括增//)
db.session.rollback()   数据库的回滚操作
db.session.delete(user) 删除数据库(需跟上commit)
db.session.commit()

db.create_all() # 创建表:
db.drop_all()    # 删除表
#查询操作
#常用的SQLAlchemy查询过滤器
filter()	#把过滤器添加到原查询上,返回一个新查询
filter_by()	#把等值过滤器添加到原查询上,返回一个新查询
limit	    #使用指定的值限定原查询返回的结果
offset()	#偏移原查询返回的结果,返回一个新查询
order_by()	#根据指定条件对原查询结果进行排序,返回一个新查询
group_by()	#根据指定条件对原查询结果进行分组,返回一个新查询

#SQLAlchemy查询
all()	#以列表形式返回查询的所有结果
first()	#返回查询的第一个结果,如果未查到,返回None
first_or_404()	#返回查询的第一个结果,如果未查到,返回404
get()	#返回指定主键对应的行,如不存在,返回None
get_or_404()	#返回指定主键对应的行,如不存在,返回404
count()	#返回查询结果的数量
paginate()	#返回一个Paginate对象,它包含指定范围内的结果

2. 数据的增删改查

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/test'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
# 使用应用程序对象作为参数创建SQLAlchemy类的对象。该对象包含用于ORM操作的辅助函数。它还提供了一个父Model类,使用它来声明用户定义的模型。在下面的代码段中,创建了students模型。
db = SQLAlchemy(app)


class Role(db.Model):
    # 定义表名
    __tablename__ = 'roles'
    # 定义列对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    user = db.relationship('User', backref='role')  # 一对多

    # repr()方法显示一个可读字符串
    def __repr__(self):
        return f'<Role: {self.name}-{self.id}>'


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, index=True)
    email = db.Column(db.String(32), unique=True)
    password = db.Column(db.String(32))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return f'<User: {self.name}-{self.id}-{self.email}-{self.password}>'

# 数据的增删改查
@app.route('/a')
def index():
    db.create_all()
    return "创建表成功"

@app.route('/upd')
def index1():
    # 修改数据
    role = Role()
    role.name = 'lisi'
    db.session.commit()
    return "更新成功"

@app.route('/ins')
def index2():
    # role = Role(name='admin')
    # db.session.add(role)
    # db.session.commit()
    # 添加一条User数据, 数据有误可以使用回滚, 将add的对象从session移除
    # user = User(name='zhangsan')
    # db.session.add(user)
    # db.session.rollback()
    # user.role_id = 1
    # db.session.add(user)
    # db.session.commit()
    # 插入一条角色数据
    role = Role(name='dmin')
    db.session.add(role)
    db.session.commit()
    # 一次插入多条数据
    user1 = User(name='zs', role_id=role.id)
    user2 = User(name='ls', role_id=role.id)
    db.session.add_all([user1, user2])
    db.session.commit()
    # 通过角色直接查询到用户信息
    # 通过用户直接查询到角色信息
    print(role.user)
    print(user1.role)
    print(user2.role)
    return "添加成功"

@app.route('/del')
def index3():
    # 删除数据
    # db.session.delete(user)
    # db.session.commit()
    db.drop_all()
    return "删除表成功"

@app.route('/query')
def index4():
    # all()返回查询到的所有对象
    res=User.query.all()
    print(User.query.all())
    for i in res:
        print(i.name)
    # 查询有多少个用户User.query.count()
    # 查询第1个用户User.query.first()
    # 查询id为4的用户[3种方式]
    # filter_by直接用属性名,比较用=, filter用类名.属性名,比较用==
    # filter_by用于查询简单的列名,不支持比较运算符
    # filter比filter_by的功能更强大,支持比较运算符,支持or_、in_等语法。
    #User.query.get(3)
    #User.query.filter_by(id=3).first()
    #User.query.filter(User.id == 3).first()
    return "查询成功"

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

3.表单验证1

from flask import Flask,render_template,url_for,redirect,request
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms.validators import DataRequired
from wtforms import StringField, SubmitField, EmailField, IntegerField

app = Flask(__name__)
manager = Manager(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SECRET_KEY']='s'
db = SQLAlchemy(app)
# 第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
migrate = Migrate(app, db)
# manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令
manager.add_command('db', MigrateCommand)

#定义模型类-作者
class Author(db.Model):
    __tablename__ = 'author'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32),unique=True)
    email = db.Column(db.String(64))
    au_book = db.relationship('Book',backref='author')
    def __str__(self):
        return f'Author:{self.name}'
#定义模型类-书名
class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer,primary_key=True)
    info = db.Column(db.String(32),unique=True)
    leader = db.Column(db.String(32))
    au_book = db.Column(db.Integer,db.ForeignKey('author.id'))
    def __str__(self):
        return f'Book:{self.info},{self.leader}'
#创建表单类,用来添加信息
class Append(FlaskForm):
    au_info = StringField(validators=[DataRequired()])
    au_email = EmailField(validators=[DataRequired()])
    bk_info = StringField(validators=[DataRequired()])
    bk_leader = StringField(validators=[DataRequired()])
    # au_bk_id = IntegerField(validators=[DataRequired()])
    submit = SubmitField(u'添加')
@app.route('/',methods=['GET','POST'])
def index():
    # db.create_all()
    #查询所有作者和书名信息
    author = Author.query.all()
    book = Book.query.all()
    #创建表单对象
    form = Append()
    if form.validate_on_submit():
        #获取表单输入数据
        wtf_au_info= form.au_info.data
        wtf_au_email = form.au_email.data
        wtf_bk_info = form.bk_info.data
        wtf_bk_leader = form.bk_leader.data
        # wtf_au_bk_id= form.au_bk_id.data

        #把表单数据存入模型类
        auid = Author.query.filter_by(name=wtf_au_info).first()
        if auid:
            # db_au = Author(name=wtf_au_info,email=wtf_au_email)
            print(auid.id)
            db_bk = Book(info=wtf_bk_info,leader=wtf_bk_leader,au_book=auid.id)
            #提交会话
            # db.session.add_all([db_au,db_bk])
            db.session.add(db_bk)
            db.session.commit()
        else:

            db_au = Author(name=wtf_au_info,email=wtf_au_email)
            db_bk = Book(info=wtf_bk_info, leader=wtf_bk_leader)
            # 提交会话
            db.session.add(db_au)
            db.session.commit()
            db.session.add(db_bk)
            db.session.commit()
            #添加数据后,再次查询所有作者和书名信息
        author = Author.query.all()
        book = Book.query.all()
        return render_template('index.html',author=author,book=book,form=form)
    else:
        if request.method=='GET':
            render_template('index.html', author=author, book=book,form=form)
    return render_template('index.html',author=author,book=book,form=form)
#删除作者
@app.route('/delete_author<id>')
def delete_author(id):
    #精确查询需要删除的作者id
    au = Author.query.filter_by(id=id).first()
    db.session.delete(au)
    #直接重定向到index视图函数
    return redirect(url_for('index'))
#删除书名
@app.route('/delete_book<id>')
def delete_book(id):
    #精确查询需要删除的书名id
    bk = Book.query.filter_by(id=id).first()
    db.session.delete(bk)
    #直接重定向到index视图函数
    return redirect(url_for('index'))
if __name__ == '__main__':
    app.run(debug=True)


<form method="post">
    {{ form.csrf_token }}
    <p>作者:{{ form.au_info }}</p>
    <p>电子邮件:{{ form.au_email }}</p>
    <hr>
    <p>书名:{{ form.bk_info }}</p>
    <p>主角:{{ form.bk_leader }}</p>
{#        <p>关联id:{{ form.au_bk_id }}</p>#}
    <p>{{ form.submit }}</p>
</form>
    <ul>
        {% for x in author %}
        <li>作者:{{ x.name }} 电子邮件:{{ x.email }} <a href='/delete_author{{ x.id }}'> 删除</a></li>
        {% endfor %}
    </ul>
    <hr>
    <ul>
        {% for x in book %}
        <li>书名:{{ x.info }} 主角:{{ x.leader }} 关联id:{{ x.au_book }} <a href='/delete_book{{ x.id }}'>删除</a></li>
        {% endfor %}
    </ul>

4.表单验证2

#  1. 调用wtf的函数实现验证
    if book_form.validate_on_submit():
        # 2. 验证通过获取数据
        author_name = book_form.author.data
        book_name = book_form.book.data
        # 3. 判断作者是否存在
        author = Author.query.filter_by(name=author_name).first()
        if author:
            # 4. 判断书籍是否存在, 没有重复书籍就添加数据. 如果重复就提示错误
            book = Book.query.filter_by(name=book_name).first()
            if book:
                # 如果重复就提示错误
                flash('已存在同名书籍')
            else:
                # 没有重复书籍就添加数据
                try:
                    new_book = Book(name=book_name, author_id=author.id)
                    db.session.add(new_book)
                    db.session.commit()
                except Exception as e:
                    print e
                    flash('书籍添加失败')
                    db.session.rollback()
        else:
            # 5. 如果作者不存在, 添加作者和书籍
            try:
                new_author = Author(name=author_name)
                db.session.add(new_author)
                db.session.commit()
                new_book = Book(name=book_name, author_id=new_author.id)
                db.session.add(new_book)
                db.session.commit()
            except Exception as e:
                print e
                flash('添加失败')
                db.session.rollback()
    else:
        # 6. 验证不通过提示错误
        if request.method == 'POST':
            flash('参数不完整')

总结

有关于model层的操作,很是重要。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

joyyi9

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值