Flask中数据库的应用

一、配置SQLAlchemy

1.安装包

pip install flask-sqlalchemy
pip install pymysql

2.配置数据库

a)配置SQLALCHEMY_DATABASE_URI SQLALCHEMY_TRACK_MODIFICATIONS

>>>root 用户名
>>>password 密码
>>>localhost 数据库地址:本地数据库 / 服务器地址

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:passowrd@localhost:3306/数据库名称'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
b)初始化
SQLAlchemy(app=app)

二、model模型

1.数据类型

a)String(长度) 字符串
b)Integer 整数
c)Date 时间

2.参数

a)primary_key 主键
b)autoincrement 从1开始,每次自动增加1
c)unique 唯一
d)default 默认
e)nullable 是否允许为空值

3.创建模型

a)知识点:

>>>db = SQLAlchemy() 实例化
>>>db.Model 继承model类
>>>db.Column() 插入属性
>>>db.String(20) 数据类型
>>>__tablename__ 指定表名称
>>>def __init__(self, 参数1, 参数2) 模型初始化
初始化的作用:在创建实例时非常方便,如创建一个姓名为王小,年龄20的学生,可以直接写作:Student('王小', 20)

b)实例

创建一个学生模型,保存学生姓名、年龄信息。

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20), unique=True)
    s_age = db.Column(db.Integer, default=18)

    __tablename__ = 'student'


    def __init__(self, name, age):
        self.s_name = name
        self.s_age = age

创建一个班级模型,保存班级名称、班级描述、班级创建时间信息。

class Grade(db.Model):

    g_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    g_name = db.Column(db.String(10), unique=True)
    g_desc = db.Column(db.String(100),nullable=True)
    g_time = db.Column(db.Date, default=datetime.now)

    __tablename__ = 'grade'

    def __init__(self, name, desc):
        self.g_name = name
        self.s_desc = desc

>>>注意:Flask中创建的模型,不会自动创建id字段,需要自己定义。

4.一对多关系

通过如下实例阐述flask中一对多关系。
实例:给上述的学生表添加一个s_grade外键,链接到班级表,指定每个学生所在的班级。

a)学生表中添加s_grade字段:

>>>必须先指定s_grade的数据类型db.Integer,再指定外键信息db.ForeignKey。
>>>db.ForeignKey(‘参数’)
参数grade.g_id含义:grade是被关联表中__tablename__ 指定的表名称,g_id是被关联表的主键名。

s_grade = db.Column(db.Integer, db.ForeignKey('grade.g_id'), nullable=True)
b)班级表中添加students字段:

在django中设置外键时只需要在要设置外键的表中添加外键,而不需要在被关联表中进行任何操作。但是在SQLAlchemy建模中,还需要在被关联的模型中添加关系。这里在Grade模型中新建了一个名叫students的属性用来表示当前班级中包含的学生列表。
格式:db.relationship(‘参数1’, backref='参数2', lazy=True)

students = db.relationship('Student', backref='stu', lazy=True)

如上所示,students被定义成一个db.relationship对象,该对象的构造函数由两部分组成:
>>>第一部分: 'Student'表示关系的另一端模型的名称.
>>>第二部分: 是一个名叫backref的参数,叫做反向关系,我们将其设置成'stu',它会像Student模型中添加一个名叫做stu的属性,这个属性可以替代s_grade访问Grade模型,但是它获取的是Grade模型的对象,而非Grade模型对应的g_id的值。

c)一对多的应用

实例1:通过学生id查询学生的信息,和该学生所在班级的信息
>>>a)视图

@grade.route('/selectgradebystu/<int:stuid>/')
def select_grade_by_stu(stuid):

    stu = Student.query.get(stuid)
    grade = stu.stu

    return render_template('student_grade.html', stu=stu, grade=grade)

>>>b)html页面解析


{% extends 'base_main.html' %}

{% block title %}
    根据学生查询班级
{% endblock %}

{% block content %}
    学生编号:{{ stu.s_id }}
    学生姓名:{{ stu.s_name }}
    学习年龄:{{ stu.s_age }}
    班级名称:{{ grade.g_name }}
{% endblock %}

>>>c)演示结果


>>>d)比对数据库


image.png

实例2:通过班级id查找班级所有学生信息
>>>a)视图

@grade.route('/selectstubygrade/<int:gradeid>/')
def select_stu_by_grade(gradeid):

    grade = Grade.query.get(gradeid)
    stus = grade.students

    return render_template('grade_student.html', grade=grade, stus=stus)

>>>b)html页面解析


{% extends 'base_main.html' %}

{% block title %}
    班级找学生
{% endblock %}

{% block content %}
    班级编号:{{ grade.g_id }}
    <ul>
    {% for stu in stus %}
        <li>
        学生编号:{{ stu.s_id }}
        学生姓名:{{ stu.s_name }}
        学生年龄:{{ stu.s_age }}
        </li>
    {% endfor %}

    </ul>

{% endblock %}

>>>c)演示结果


>>>d)比对数据库


知识点:

1.想通过外键所在表查询被关联表的信息,不使用外键,而是使用backref指定的名称。


2.想通过被关联表查询外键所在表信息,使用被关联表中添加的字段名称即可。


5.多对多关系

多对多关系:假设存在一个学生表,和一个课程表,一个学生可以选择多门课程,一门课程可以被多个学生选择,那么学生和课程之间就是多对多的关系。
>>>学生表

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(20), unique=True)
    s_age = db.Column(db.Integer, default=18)

    __tablename__ = 'student'

    def __init__(self, name, age):
        self.s_name = name
        self.s_age = age

>>>课程表

class Course(db.Model):
    c_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    c_name = db.Column(db.String(10), unique=True)

    __tablename__ = 'course'

    def __init__(self, name):
        self.c_name = name

flask中多对多关系仍使用定义一对多关系的 db.relationship() 方法进行定义,但在多对多关系中,增加了 secondary 参数,用于指定关联表。此处的关联表是需要单独创建的一个表,不是模型,SQLAlchemy 会自动接管这个表。多对多关系可以在关联的两个类中的任何一个类中定义, backref 参数会处理好关系的另一侧。

a)创建关联表

格式:db.Table('参数1‘, db.Column('参数2', db.参数3, db.ForeignKey('参数4')))
>>>参数1:关联表的名称
>>>参数2:字段名称
>>>参数3:数据类型
>>>参数4:外键名称,格式和一对多中格式相同

sc = db.Table('sc',
              db.Column('s_id', db.Integer, db.ForeignKey('student.s_id'), primary_key=True),
              db.Column('c_id', db.Integer, db.ForeignKey('course.c_id'), primary_key=True)
              )

b)在任意一个类中添加字段:

格式:db.relationship('参数1', secondary=参数2, backref='参数3')
>>>参数1:关联的另一个类名称
>>>参数2:关联表的表名称
>>>参数3:想要用另一个类调用这个类的信息时,就需要使用此参数,参数名称可自行定义。
如下在课程表中添加students字段,相当于给课程表添加了students属性,通过这个属性可以获取学生的信息,并且学生可以通过cou属性获取课程信息。

students = db.relationship('Student', secondary=sc, backref='cou')

c)多对多的应用

实例1:添加学生选课信息,一次只添加一门课程

>>>a)视图

@stu.route('/stucou/', methods=['GET', 'POST'])
def stu_cou():

    if request.method == 'GET':
        stus = Student.query.all()
        cous = Course.query.all()
        return render_template('stu_cou.html', stus=stus, cous=cous)
    else:
        s_id = request.form.get('student')
        c_id = request.form.get('course')

        stu = Student.query.get(s_id)
        cou = Course.query.get(c_id)

        cou.students.append(stu)
        db.session.add(cou)
        db.session.commit()

        return '学生选课成功'

>>>b)html页面解析


{% extends 'base_main.html' %}

{% block title %}
    学生课程信息
{% endblock %}

{% block extCSS %}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/h3.css') }}">
{% endblock %}

{% block content %}
    <form action="" method="post">

        <h3>学生1信息:</h3>
        <br>
        <select name="student" id="">
            <option value="">请选择学生信息</option>
            {% for stu in stus %}
                <option value="{{ stu.s_id }}">{{ stu.s_name }}</option>
            {% endfor %}
        </select>
        <br>
        <h3>课程信息:</h3>
        <select name="course" id="">
            <option value="">请选择课程信息</option>
            {% for cou in cous %}
                <option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
            {% endfor %}
        </select>
        <br>
        <input type="submit" value="提交">

    </form>

{% endblock %}

>>>c)演示结果


>>>d)比对数据库
点击提交,会在数据库sc表中创建一条记录


实例2:添加学生选课信息,一次添加多门课程

>>>a)视图

@stu.route('/stucou/', methods=['GET', 'POST'])
def stu_cou():

    if request.method == 'GET':
        stus = Student.query.all()
        cous = Course.query.all()
        return render_template('stu_cou.html', stus=stus, cous=cous)
    else:
        s_id = request.form.get('student')
        c_ids = request.form.getlist('course')

        stu = Student.query.get(s_id)
        for c_id in c_ids:
            cou = Course.query.get(c_id)
            cou.students.append(stu)
            db.session.add(cou)
            db.session.commit()

        return '学生选课成功'

>>>html页面解析


{% extends 'base_main.html' %}

{% block title %}
    学生课程信息
{% endblock %}

{% block extCSS %}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/h3.css') }}">
{% endblock %}

{% block content %}
    <form action="" method="post">

        <h3>学生1信息:</h3>
        <br>
        <select name="student" id="">
            <option value="">请选择学生信息</option>
            {% for stu in stus %}
                <option value="{{ stu.s_id }}">{{ stu.s_name }}</option>
            {% endfor %}
        </select>
        <br>
        <h3>课程信息:</h3>
        <select name="course" id="">
            <option value="">请选择课程信息</option>
            {% for cou in cous %}
                <option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
            {% endfor %}
        </select>
        <br>
        <select name="course" id="">
            <option value="">请选择课程信息</option>
            {% for cou in cous %}
                <option value="{{ cou.c_id }}">{{ cou.c_name }}</option>
            {% endfor %}
        </select>
        <br>
        <input type="submit" value="提交">

    </form>

{% endblock %}

>>>演示结果


>>>比对数据库


实例3:学生查询选课信息

>>>a)视图

# 查询所有学生信息
@stu.route('/allstu/')
def all_stu():
    stus = Student.query.all()
    return render_template('all_stu.html', stus=stus)


# 查询学生选课信息
@stu.route('/selectcoubystu/<int:id>/')
def select_cou_by_stu(id):

    stu = Student.query.get(id)
    cous = stu.cou

    return render_template('stucourse.html', cous=cous, stu=stu)

>>>b)all_stu.html页面解析

{% extends 'base_main.html' %}

{% block title %}
    所有学生信息
{% endblock %}

{% block content %}
    <ul>
    {% for stu in stus %}
        <li>
            id:{{ stu.s_id }}
            姓名:{{ stu.s_name }}
            <a href="/stu/selectcoubystu/{{ stu.s_id }}">所选课程</a>
        </li>
    {% endfor %}

    </ul>
{% endblock %}

>>>c)演示结果:


>>>比对数据库:


实例4:删除学生的某条选课信息

>>>a)视图

@stu.route('/deletecoubyid/<int:s_id>/<int:c_id>/')
def delete_course_by_id(s_id, c_id):

    stu = Student.query.get(s_id)
    cou = Course.query.get(c_id)

    cou.students.remove(stu)
    db.session.commit()

    return redirect(url_for('stu.all_stu'))

>>>b)stucourse.html页面解析


{% extends 'base_main.html' %}

{% block title %}
    学生选课信息
{% endblock %}

{% block content %}
    {{ stu.s_name }}选课结果:
    <ul>
    {% for cou in cous %}
        <li>
            id:{{ cou.c_id }}
            课程:{{ cou.c_name }}
            <a href="/stu/deletecoubyid/{{ stu.s_id }}/{{ cou.c_id }}/">删除</a>
        </li>
    {% endfor %}

    </ul>
{% endblock %}

>>>c)演示结果


>>>d)对比数据库
点击id=4的对应的删除,数据库中会删除对应数据,如下图,数据库中s_id=1 c_id=4 的记录已经被删除。


三、数据库的操作

1.创建表create_all()

@stu.route('/createtable/')
def create_db():
    db.create_all()
    return '创建成功'

2.删除表drop_all()

a)删除db中所有表

@stu.route('/dropalltable/')
def drop_all_table():
    db.drop_all()
    return '删除成功'

b)删除db中某个表

@stu.route('/droponetable/')
def drop_one_table():
    sql = 'delete table student'
    db.sesion.execute(sql)
    db.session.commit()
    return '删除成功'

3.插入 / 创建实例

>>>注意:最后必须要commit才会真正的在数据库中插入数据,否则数据只会保存在缓存区。为了保证事务的一致性,可以用使用try except捕获异常,如果没有执行commit,就回滚上一步操作。

a)模型未初始化
@stu.route('/createstu/')
def create_stu():

    stu = Student()
    stu.s_name = 'lp%d' % random.randrange(1000)
    stu.s_age = '%d' % random.randrange(20)

    db.session.add(stu)
    try:
        db.session.commit()
    except:
        db.session.rollback()
    return '创建学生成功'
b)模型初始化
@stu.route('/createstu/')
def create_stu():

    stu = Student(random.randrange(1000), random.randrange(20))

    db.session.add(stu)
    try:
        db.session.commit()
    except:
        db.session.rollback()
    return '创建学生成功'
c)插入多条记录 add_all([ ])
def create_stu():

        stu1 = Student(username1, age1)
        stu2 = Student(username2, age2)
        stu_list = [stu1, stu2]

        db.session.add_all(stus)
        try:
            db.session.commit()
        except:
            db.session.rollback()

    return '创建学生成功'

4.查询

a)查询所有数据

>>>方式1:模型.query.all()

用这种方式查询的结果是一个 list 而不是 queryset

@stu.route('/stulist/')
def stu_all():

    stus = Student.query.all()

    return render_template('stulist.html', stus=stus)
>>>方式2:原生sql语句 session.execute(sql)
@stu.route('/stulist/')
def stu_all():

    sql = 'select * from student;'
    stus = db.session.execute(sql)

    return render_template('stulist.html', stus=stus)

b)筛选数据

>>>方式1:使用sql语句
@stu.route('/studetail/')
def stu_detail():

    sql = 'select * from student where s_name="cy406" '
    stus = db.session.execute(sql)

    return render_template('stulist.html', stus=stus)
>>>方式2:使用 模型.query.属性
(1)filter(模型.字段.运算符 值)
@stu.route('/studetail/')
def stu_detail():

    stus = Student.query.filter(Student.s_name == 'cy253')

    return render_template('stulist.html', stus=stus)
运算符:

>>>==等于
实例:查询年龄等于18的学生

stus = Student.query.filter(Student.s_age == 18)

>>>__gt__大于
实例:查询年龄大于18的学生

stus = Student.query.filter(Student.s_age.__gt__(18))

>>>__lt__小于
实例:查询年龄小于18的学生

stus = Student.query.filter(Student.s_age.__lt__(18))

>>>__ge__大于等于
实例:查询年龄大于等于18的学生

stus = Student.query.filter(Student.s_age.__ge__(18))

>>>__le__小于等于
实例:查询年龄小于等于18的学生

stus = Student.query.filter(Student.s_age.__le__(18))

>>>in_([值, 值, 值]) 包含在某些值中
实例:查询年龄在16, 18, 20, 23 中的学生

stus = Student.query.filter(Student.s_age.in_([16, 18, 20, 23]))
(2)filter_by(字段 运算符 值)
stus = Student.query.filter_by(s_name='cy716')
(3)order_by('字段')

order_by默认升序,降序排列在字段前面加减号,如下:order_by('-字段')。
实例:按照年龄降序展示所有学生信息

stus = Student.query.order_by('-s_age')
(4)limit(显示条数)

实例:显示年龄最大的三个学生

stus = Student.query.order_by('-s_age').limit(3)
(5)offset(number) 跳过几条数据

实例:跳过前3条记录,显示2条记录,即显示第4条和第5条记录

stus = Student.query.order_by('-s_age').offset(3).limit(2)
(6)get(值)

flask中,get获取的是一个列表,如果每页获取到内容,get返回一个空列表,get中的参数对应主键字段。
实例:获取id为3的学生

stus = Student.query.get(3)
(7)and_ 并且

实例:查询 id 大于5 且 年龄为18 的学生

stus = Student.query.filter(and_(Student.s_age == 18, Student.s_id>5))
(8)or_ 或

实例:查询年龄大于18 或者 名字为 王小的学生

stus = Student.query.filter(or_(Student.s_age > 18, Student.s_name == '王小'))
(9)not_ 非

not_只能加一个限制条件
实例:查询年龄不是18的学生

stus = Student.query.filter(not_(Student.s_age == 18))

5.删除实例

@stu.route('/deletestu/')
def delete_stu():

    stu = Student.query.filter_by(s_id=1).first()
    db.session.delete(stu)
    db.session.commit()

    return redirect(url_for('stu.stu_all'))

6.更新/修改实例

>>>方式1:

@stu.route('/updatestu/')
def update_stu():

    stu = Student.query.filter_by(s_id=5).first()
    stu.s_name = '王小二'
    db.session.commit()

    return redirect(url_for('stu.stu_all'))

>>>方式2:update

@stu.route('/updatestu/')
def update_stu():

    Student.query.filter(Student.s_id == '1').update({'s_name': '王大锤'})
    db.session.commit()

    return redirect(url_for('stu.stu_all'))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容