mysql 追踪ip操作_年薪百万之路--第七十三天 Flask框架之数据库操作

5f8195e55a6a91b370b9c1d77af6e35e.png

数据库连接设置

在 Flask-SQLAlchemy 中,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的 SQLALCHEMY_DATABASE_URI 键中

config.py,配置文件代码:

class Config(object):
    DEBUG = True
    SECRET_KEY = "*(%#4sxcz(^(#$#8423"
    # 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8"

其他设置:

# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
#查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True

配置完成需要去 MySQL 中创建项目所使用的数据库

$ mysql -uroot -p123
mysql > create database students charset=utf8mb4;

常用的SQLAlchemy字段类型

Integer          int                     普通整数,一般是32位
SmallInteger     int                      取值范围小的整数,一般是16位
BigInteger       int或long               不限制精度的整数
Float           float                     浮点数
Numeric         decimal.Decimal           普通数值,一般是32位 
String          str                      变长字符串
Text            str                      变长字符串,对较长或不限长度的字符串做了优化
Unicode          unicode                 变长Unicode字符串
UnicodeText      unicode                变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean          bool                   布尔值
Date            datetime.date            日期
Time            datetime.datetime       日期和时间
LargeBinary     str                      二进制文件

常用的SQLAlchemy列约束选项

primary_key         如果为True,代表表的主键
unique              如果为True,代表这列不允许出现重复的值
index               如果为True,为这列创建索引,提高查询效率
nullable            如果为True,允许有空值,如果为False,不允许有空值
default             为这列定义默认值

数据库基本操作

  • 在Flask-SQLAlchemy中,添加、修改、删除操作,均由数据库会话管理。
    • 会话用 db.session 表示。在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db.commit() 方法提交会话。
  • 在 Flask-SQLAlchemy 中,查询操作是通过 query 对象操作数据。
    • 最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据库查询。

定义模型类

from flask import Flask
# 初始化
app = Flask(import_name=__name__)

# 声明和加载配置
class Config():
    DEBUG = True
    # 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8"
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 显示原始SQL语句
    SQLALCHEMY_ECHO = True

app.config.from_object(Config)

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象
db.init_app(app)  # 初始化数据库链接

class Student(db.Model):
    # 表结构声明
    __tablename__ = "tb_student"

    # 字段声明
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")

    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

@app.route(rule='/')
def index():
    return "ok"

if __name__ == '__main__':
    # 运行flask
    app.run(debug=True)

数据表操作

创建和删除表

创建表

if __name__ == '__main__':
    # 运行flask
     db.create_all()

    app.run(debug=True)
# 注意,create_all()方法执行的时候,需要放在模型的后面
# 上面这段语句,后面我们需要转移代码到flask-script的自定义命令中。
# 执行了一次以后,需要注释掉。

删除表

db.drop_all()

代码:

from flask import Flask
# 初始化
app = Flask(import_name=__name__)

# 声明和加载配置
class Config():
    DEBUG = True
    # 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8"
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 显示原始SQL语句
    SQLALCHEMY_ECHO = True

app.config.from_object(Config)

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象
db.init_app(app)  # 初始化数据库链接

class Student(db.Model):
    # 表结构声明
    __tablename__ = "tb_student"

    # 字段声明
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")

    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

@app.route(rule='/')
def index():
    return "ok"

if __name__ == '__main__':
    with app.app_context():
        # db.drop_all()   # 删除所有的数据表
        db.create_all() # 创建所有的数据表
    # 运行flask
    app.run(debug=True)

数据操作

添加一条数据

student1 = Student(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
db.session.add(student1)
db.session.commit()

一次插入多条数据

st1 = Student(name='wang',email='wang@163.com',age=22)
st2 = Student(name='zhang',email='zhang@189.com',age=22)
st3 = Student(name='chen',email='chen@126.com',age=22)
st4 = Student(name='zhou',email='zhou@163.com',age=22)
st5 = Student(name='tang',email='tang@163.com',age=22)
st6 = Student(name='wu',email='wu@gmail.com',age=22)
st7 = Student(name='qian',email='qian@gmail.com',age=22)
st8 = Student(name='liu',email='liu@163.com',age=22)
st9 = Student(name='li',email='li@163.com',age=22)
st10 = Student(name='sun',email='sun@163.com',age=22)
db.session.add_all([st1,st2,st3,st4,st5,st6,st7,st8,st9,st10])
db.session.commit()

删除数据

# 方法1
student = Student.query.first()
db.session.delete(student)
db.session.commit()

# 方法2【事务中使用,就是乐观锁】
ret = Student.query.filter(Student.name=='sun').delete()
db.session.commit()

更新数据

# 方法1
student = Student.query.first()
student.name = 'dong'
db.session.commit()

# 方法2【事务中使用,就是乐观锁】
ret = Student.query.filter(Student.name == 'liu').update({'money': 1000})
db.session.commit()

# 方法3【批量操作, 实现类似django里面F函数的效果】
ret = Student.query.filter(Student.age == 22).update({Student.money: Student.money+'200'})
db.session.commit()

数据基本查询

常用的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分页器对象,它包含指定范围内的结果
having               返回结果中符合条件的数据,必须跟在group by后面,其他地方无法使用。

get():参数为数字,表示根据主键查询数据,如果主键不存在返回None

Student.query.get()

all()返回查询到的所有对象

Student.query.all()

first()返回查询到的第一个对象【first获取一条数据,all获取多条数据】

Student.query.first()

filter模糊查询,支持各种运算符和查询方法

返回名字结尾字符为g的所有数据。

    # name姓名中以"g"结尾的学生
    ret = Student.query.filter(Student.name.endswith("g")).all()
    # name姓名中包含"u"的学生
    ret = Student.query.filter(Student.name.contains("u")).all()
    # name姓名中以"w"开头的学生
    ret = Student.query.filter(Student.name.startswith("w")).all()
    
    
    # 也可以使用filter进行精确查找,
    # 则需要指定条件格式为: 模型.字段 比较运算符 值。
    # 运算符可以是: ==表示相等,!=不相等,> 表示大于  < 表示小于,>=大于等于,<=小于等于
    # ret = Student.query.filter(Student.age==22).all()

    # 另一种写法的查询方式
    # db.session.query(Student) 相当于 Student.query
    # ret = db.session.query(Student).filter(Student.age==22).all()
    

filter_by精确查询,只支持字段的值是否相等这种条件

例如:返回名字等于wang的学生学生

# name=wang的学生
ret = Student.query.filter_by(name="wang").first()
# age = 22的所有学生
ret = Student.query.filter_by(age=22).all()

多条件查询

逻辑非,返回名字不等于wang的所有数据

Student.query.filter(Student.name!='wang').all()

not_ 相当于取反

from sqlalchemy import not_
Student.query.filter(not_(Student.name=='wang')).all()

逻辑与,需要导入and,返回and()条件满足的所有数据

from sqlalchemy import and_
Student.query.filter(and_(Student.name!='wang',Student.email.endswith('163.com'))).all()

逻辑或,需要导入or_

from sqlalchemy import or_
Student.query.filter(or_(Student.name!='wang',Student.email.endswith('163.com'))).all()

in_范围查询

"""查询id为2, 3, 5, 7, 8这几个学生信息"""
student_list = Student.query.filter(Student.id.in_([2, 3, 5, 7, 8])).all()
print(student_list)

order_by 排序

# 查询所有学生,并按年龄进行倒序排列
ret = Student.query.order_by(Student.age.desc()).all()

# 查询所有学生,并按年龄进行倒序排列,年龄相同,则按id进行降序排序.
ret = Student.query.order_by(Student.age.desc(),Student.id.desc()).all()

count统计

# 查询age>=19的男生的数量
    from sqlalchemy import and_
    # ret = Student.query.filter( and_(Student.age>=19,Student.sex==True) ).count()
    ret = Student.query.filter( Student.age>=19, Student.sex==True ).count()

对结果进行偏移量和数量的限制

    # 查询年龄最大的3个学生
    ret1 = Student.query.order_by(Student.age.desc()).limit(3).all()

    # 查询年龄排第4到第7名的学生
    ret2 = Student.query.order_by(Student.age.desc(),Student.id.desc()).offset(4).limit(4).all()
    print(ret1,ret2)

分页器的使用

run.py,代码:

from flask import Flask,request,jsonify,render_template
from config import Config
from models import db,Student,Course,Teacher

# 初始化
app = Flask(import_name=__name__,template_folder='templates')
app.config.from_object(Config)
db.init_app(app)  # 初始化数据库链接

"""分页器使用"""
@app.route(rule="/list")
def list():
    pagination = Student.query.paginate(per_page=3)

    # 获取当前页面所有数据
    # print( pagination.items )
    # data = {
    #     "items": [],
    #     "pages": pagination.pages,
    #     "page": pagination.page,
    #     "has_prev": pagination.has_prev,
    #     "has_next": pagination.has_next,
    # }

    # for item in pagination.items:
    #     data["items"].append({
    #         "id": item.id,
    #         "sex": "男" if item.sex else "女",
    #         "age": item.age,
    #         "name": item.name,
    #     })
    #
    # if pagination.has_prev:
    #     print( pagination.prev() ) # 上一页数据的分页器对象
    #     print( pagination.prev().items ) # 上一页数据
    #
    # if pagination.has_next:
    #     print( pagination.next() ) # 下一页数据的分页器对象
    #     print( pagination.next().items ) # 下一页数据

    return render_template("list.html",pagination=pagination)

if __name__ == '__main__':
    # 运行flask
    app.run - 这个网站可出售。 - 最佳的app 来源和相关信息。(debug=True)

list.html,代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    .page a,.page span{
        padding: 2px 6px;
        color: #fff;
        background: #6666ff;
        text-decoration: none;
    }
    .page span{
        color: #fff;
        background: orange;
    }

    </style>
</head>
<body>
    <table border="1" align="center" width="600">
        <tr>
           <th>ID</th>
           <th>age</th>
           <th>name</th>
           <th>sex</th>
           <th>money</th>
        </tr>
        {% for student in pagination.items %}
        <tr>
           <td>{{ student.id }}</td>
           <td>{{ student.age }}</td>
           <td>{{ student.name }}</td>
           <td>{{ "男" if student.sex else "女" }}</td>
           <td>{{ student.money }}</td>
        </tr>
        {% endfor %}
        <tr align="center">
            <td colspan="5" class="page">
                {% if pagination.has_prev %}
                <a href="?page=1">首  页</a>
                <a href="?page={{ pagination.page-1 }}">上一页</a>
                <a href="?page={{ pagination.page-1 }}">{{ pagination.page-1 }}</a>
                {% endif %}
                <span>{{ pagination.page }}</span>
                {% if pagination.has_next %}
                <a href="?page={{ pagination.page+1 }}">{{ pagination.page+1 }}</a>
                <a href="?page={{ pagination.page+1 }}">下一页</a>
                <a href="?page={{ pagination.pages }}">尾  页</a>
                {% endif %}
            </td>
        </tr>
    </table>
</body>
</html>

分组查询和分组查询结果过滤

一般分组都会结合聚合函数来一起使用。SQLAlchemy中所有的聚合函数都在func模块中声明的。

from sqlalchemy import func

func.count        统计总数
func.avg         平均值
func.min          最小值
func.max         最大值
func.sum         和

代码:

# 查询当前所有男生女生的数量
from sqlalchemy import func
    # ret = db.session.query(Student.sex,func.count(Student.id)).group_by(Student.sex).all()
    # 查询当前不同年龄的学生数量
    ret = db.session.query(Student.age,func.count(Student.id)).group_by(Student.age).having(Student.age>19).all()
    
    # 查询男生和女生中,年龄最小的是几岁?
    ret = db.session.query(Student.sex,func.min(Student.age)).group_by(Student.sex).all()

执行原生SQL语句

# 读取多条数据
ret = db.session.execute("select * from tb_student").fetchall()
# 读取一条数据
ret = db.session.execute("select * from tb_student").fetchone()
# 添加/修改/删除
db.session.execute("UPDATE tb_student SET money=(tb_student.money + %s) WHERE tb_student.age = %s" % (200, 22))
    db.session.commit()

关联查询

常用的SQLAlchemy关系选项

023e73518c2154bfc06c750ca60881e0.png

模型之间的关联

一对一

class Student(db.Model):
    """个人信息主表"""
	....
    # 关联属性,这个不会被视作表字段,只是模型的属性。
    # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据
    info = db.relationship("StudentInfo",uselist=False,backref="own")


class StudentInfo(db.Model):
    """个人信息附加表"""

    # 外键,
    # 如果是一对一,则外键放在附加表对应的模型中
    # 如果是一对多,则外键放在多的表对象的模型中
    uid = db.Column(db.Integer, db.ForeignKey(Student.id),comment="外键")

课堂代码:

run.py,代码:

from flask import Flask,request,jsonify,render_template
from config import Config
from models2 import db,Student,Course,Teacher,StudentInfo

# 初始化
app = Flask(import_name=__name__,template_folder='templates')
app.config.from_object(Config)
db.init_app(app)  # 初始化数据库链接

@app.route(rule='/')
def index():
    """1对1模型操作"""
    # 获取数据[从主表读取数据,获取附加表数据]
    # student = Student.query.get(3)
    # print( student.info.address )
    # print( student.info.edu )

    # 获取数据[从附加表读取数据,获取主表数据]
    # student_info = StudentInfo.query.filter(StudentInfo.address=="北京市昌平区沙河地铁站对面").first()
    # print(student_info.own.name)

    # 添加数据[添加数据,把关联模型的数据也一并添加]
    # student = Student(name="liu", sex=True, age=22, email="33523@qq.com", money=100)
    # student.info = StudentInfo(address="深圳市宝安区创业2路103号", edu="本科")
    # db.session.add(student)
    # db.session.commit()

    # 修改数据[通过主表可以修改附加表的数据,也可以通过附加表模型直接修改主表的数据]
    # student = Student.query.get(4)
    # student.info.address = "广州市天河区天河东路103号"
    # db.session.commit()

    return "ok"

if __name__ == '__main__':
    # 运行flask
    app.run(debug=True)

models.py,代码:

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象

class Student(db.Model):
    # 表名
    __tablename__ = "tb_student"
    # 字段
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")
    # 关联属性,这个不会被视作表字段,只是模型的属性。
    # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据
    info = db.relationship("StudentInfo",uselist=False,backref="own")
    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class StudentInfo(db.Model):
    # 表明
    __tablename__ = "tb_student_info"
    # 字段
    id = db.Column(db.Integer, primary_key=True, comment="主键")
    address = db.Column(db.String(299), comment="住址")
    edu = db.Column(db.Enum("高中以下","大专高技","本科","硕士","博士以上"))
    # uid = db.Column(db.Integer, db.ForeignKey("tb_student.id"),comment="外键")
    # 外键,
    # 如果是一对一,则外键放在附加表对应的模型中
    # 如果是一对多,则外键放在多的表对象的模型中
    uid = db.Column(db.Integer, db.ForeignKey(Student.id),comment="外键")

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

config.py,代码:

# 声明和加载配置
class Config():
    DEBUG = True
    # 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8"
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 显示原始SQL语句
    SQLALCHEMY_ECHO = True
    # 调整json数据转换中文的配置
    JSON_AS_ASCII=False

一对多

class Teacher(db.Model):
	...
    # 关联属性,一的一方添加模型关联属性
    course = db.relationship("Course", uselist=True, backref="teacher",lazy='dynamic')
   
class Course(db.Model):
	...
    # 外键,多的一方模型中添加外间
    teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id))
  • 其中realtionship描述了Course和Teacher的关系。第一个参数为对应参照的类"Course"
  • 第二个参数backref为类Teacher申明新属性的方法
  • 第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
    • lazy='subquery',查询当前数据模型时,采用子查询(subquery),把外键模型的属性也瞬间查询出来了。
    • lazy=True或lazy='select',查询当前数据模型时,不会把外键模型的数据查询出来,只有操作到外键关联属性时,才进行连表查询数据[执行SQL]
    • lazy='dynamic',查询当前数据模型时,不会把外键模型的数据查询出来,只有操作到外键关联属性并操作外键模型具体属性时,才进行连表查询数据[执行SQL]

models2.py,代码:

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象

class Student(db.Model):
    # 表名
    __tablename__ = "tb_student"
    # 字段
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")
    # 关联属性,这个不会被视作表字段,只是模型的属性。
    # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据
    info = db.relationship("StudentInfo",uselist=False,backref="own")
    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class StudentInfo(db.Model):
    # 表明
    __tablename__ = "tb_student_info"
    # 字段
    id = db.Column(db.Integer, primary_key=True, comment="主键")
    address = db.Column(db.String(299), comment="住址")
    edu = db.Column(db.Enum("高中以下","大专高技","本科","硕士","博士以上"))
    # uid = db.Column(db.Integer, db.ForeignKey("tb_student.id"),comment="外键")
    # 外键,
    # 如果是一对一,则外键放在附加表对应的模型中
    # 如果是一对多,则外键放在多的表对象的模型中
    uid = db.Column(db.Integer, db.ForeignKey(Student.id),comment="外键")

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    # 关联属性,一的一方添加模型关联属性
    course = db.relationship("Course", uselist=True, backref="teacher",lazy='dynamic')
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # 外键,多的一方模型中添加外间
    teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id))
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

run.py代码:

from flask import Flask,request,jsonify,render_template
from config import Config
from models2 import db,Student,Course,Teacher,StudentInfo

# 初始化
app = Flask(import_name=__name__,template_folder='templates')
app.config.from_object(Config)
db.init_app(app)  # 初始化数据库链接

@app.route(rule='/more')
def more():
    """一对多/多对一模型操作"""
    # 从1的一方的模型中获取多的一方模型的数据
    # teacher = Teacher.query.get(1)
    # print(teacher)
    # # ret = teacher.course
    # for course in teacher.course:
    #     print(course.name,course.price)

    # 从多的一方获取1的一方数据
    # course = Course.query.get(1)
    # print(course.teacher)
    # print(course.teacher.name)

    # 添加数据
    # 从1的一方添加数据,同时给多的一方也添加
    # teacher = Teacher(name="蓝老师",option="讲师")
    # teacher.course = [Course(name="插画入门",price=199.00),Course(name="素描入门",price=129.00),]
    # db.session.add(teacher)
    # db.session.commit()

    return "ok"
if __name__ == '__main__':
    # 运行flask
    app.run(debug=True)

多对多

通过db.Table创建关联模型

# 多对多。必须有关系表进行记录
student_course = db.Table("tb_student_course",
     db.Column("id", db.Integer, primary_key=True, comment="主键ID"),
     db.Column("sid", db.Integer, db.ForeignKey('tb_student.id'), comment="学生ID"),
     db.Column("cid", db.Integer, db.ForeignKey('tb_course.id'), comment="课程ID"),
)

class Student(db.Model):
	...
    course_list = db.relationship("Course",secondary=student_course,backref="student_list", lazy='dynamic')

class Course(db.Model):
	...
    # 上下2个模型只需要声明一个关系属性即可,可以通过backref反向调用。
    # student_list = db.relationship("Student",secondary=student_course,backref="course_list", lazy='dynamic')

model.py代码:

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象

# 针对多对多。
# 我们可以以db.Table创建关系表的方式进行关联
# 也可以创建一个中间表模型,进行关联[就是把原来2个模型之间的多对多转换成3个模型之间的一对多]
student_course = db.Table("tb_student_course",
     db.Column("id", db.Integer, primary_key=True, comment="主键ID"),
     db.Column("sid", db.Integer, db.ForeignKey('tb_student.id'), comment="学生ID"),
     db.Column("cid", db.Integer, db.ForeignKey('tb_course.id'), comment="课程ID"),
)

class Student(db.Model):
    # 表名
    __tablename__ = "tb_student"
    # 字段
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")
    # 关联属性,这个不会被视作表字段,只是模型的属性。
    # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据
    info = db.relationship("StudentInfo",uselist=False,backref="own")
    course_list = db.relationship("Course",secondary=student_course,backref="student_list", lazy='dynamic')
    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class StudentInfo(db.Model):
    # 表明
    __tablename__ = "tb_student_info"
    # 字段
    id = db.Column(db.Integer, primary_key=True, comment="主键")
    address = db.Column(db.String(299), comment="住址")
    edu = db.Column(db.Enum("高中以下","大专高技","本科","硕士","博士以上"))
    # uid = db.Column(db.Integer, db.ForeignKey("tb_student.id"),comment="外键")
    # 外键,
    # 如果是一对一,则外键放在附加表对应的模型中
    # 如果是一对多,则外键放在多的表对象的模型中
    uid = db.Column(db.Integer, db.ForeignKey(Student.id),comment="外键")

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    # 关联属性,一的一方添加模型关联属性
    course = db.relationship("Course", uselist=True, backref="teacher",lazy='dynamic')
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # 外键,多的一方模型中添加外间
    teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id))
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

视图代码:

from flask import Flask,request,jsonify,render_template
from config import Config
from models import db,Student,Course,Teacher,StudentInfo

# 初始化
app = Flask(import_name=__name__,template_folder='templates')
app.config.from_object(Config)
db.init_app(app)  # 初始化数据库链接

@app.route(rule='/')
def index():
    """多对多"""
    # 查询学生数据,关联查询课程
    # student = Student.query.get(3)
    # course_list = student.course_list.filter(Course.price<=300).all()
    # print( course_list )
    #
    # 查询课程数据,关联查询学生
    # course = Course.query.get(3)
    # student_list = course.student_list
    # print(student_list)
    #
    # 给学生报读课程[已经存在的课程]
    # student = Student.query.get(6)
    # course1 = Course.query.get(4)
    # course2 = Course.query.get(5)
    # student.course_list.append(course1)
    # # student.course_list.extend([course1,course2])
    # db.session.commit()
    #
    # 给学生报读新课程[没有存在的课程,添加关系之前会自动创建模型]
    # student = Student.query.get(7)
    # student.course_list.extend([
    #     Course(name="python高级1",price=199.00,teacher_id=3),
    #     Course(name="python高级2", price=199.00, teacher_id=3),
    #     Course(name="python高级3", price=199.00, teacher_id=3),
    # ])
    # db.session.commit()

    return "ok"
if __name__ == '__main__':
    # 运行flask
    app.run(debug=True)

通过中间表模型创建关联模型

把学生和课程之间的多对多拆分成,学生与学生课程记录的一对多和课程与学生课程记录的一对多。

class Student(db.Model):
	...
    # 学生和学生课程
    to_course = db.relationship("StudentCourse", uselist=True, backref="to_student", lazy='dynamic')

class Course(db.Model):
	...
    to_student = db.relationship("StudentCourse", uselist=True, backref="to_course", lazy='dynamic')

# 针对多对多。
# 创建一个中间表模型,进行关联[就是把原来2个模型之间的多对多转换成3个模型之间的一对多]
class StudentCourse(db.Model):
    __tablename__ = 'tb_student_course'
    id = db.Column(db.Integer, primary_key=True)
    sid = db.Column(db.Integer, db.ForeignKey(Student.id))
    cid = db.Column(db.Integer, db.ForeignKey(Course.id))
    created_time = db.Column(db.DateTime, nullable=True, )
    achievement = db.Column(db.Numeric(5,2), nullable=True )

    def __repr__(self):
        return 'Student:%s, Course:%s'% (self.to_student.name,self.to_course.name)

models2.py,代码:

# 初始化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象

class Student(db.Model):
    # 表名
    __tablename__ = "tb_student"
    # 字段
    id   = db.Column(db.Integer, primary_key=True, comment="主键")
    name = db.Column(db.String(64), index=True, comment="姓名")
    sex  = db.Column(db.Boolean, default=True, comment="性别")
    age  = db.Column(db.SmallInteger, nullable=True, comment="年龄")
    email = db.Column(db.String(128), unique=True, comment="邮箱地址")
    money = db.Column(db.Numeric(8,2), default=0, comment="钱包")
    # 关联属性,这个不会被视作表字段,只是模型的属性。
    # 因为StudentInfo和Student是一对一的关系,所以uselist=False表示关联一个数据
    info = db.relationship("StudentInfo",uselist=False,backref="own")
    # 学生和学生课程
    to_course = db.relationship("StudentCourse", uselist=True, backref="to_student", lazy='dynamic')
    # 自定义方法
    def __repr__(self):
        return 'Student:%s' % self.name

class StudentInfo(db.Model):
    # 表明
    __tablename__ = "tb_student_info"
    # 字段
    id = db.Column(db.Integer, primary_key=True, comment="主键")
    address = db.Column(db.String(299), comment="住址")
    edu = db.Column(db.Enum("高中以下","大专高技","本科","硕士","博士以上"))
    # uid = db.Column(db.Integer, db.ForeignKey("tb_student.id"),comment="外键")
    # 外键,
    # 如果是一对一,则外键放在附加表对应的模型中
    # 如果是一对多,则外键放在多的表对象的模型中
    uid = db.Column(db.Integer, db.ForeignKey(Student.id),comment="外键")

class Teacher(db.Model):
    # 表结构声明
    __tablename__ = 'tb_teacher'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    option = db.Column(db.Enum("讲师","助教","班主任"), default="讲师")
    # 关联属性,一的一方添加模型关联属性
    course = db.relationship("Course", uselist=True, backref="teacher",lazy='dynamic')
    def __repr__(self):
        return 'Teacher:%s' % self.name

class Course(db.Model):
    # 定义表名
    __tablename__ = 'tb_course'
    # 定义字段对象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    price = db.Column(db.Numeric(6,2))
    # 外键,多的一方模型中添加外间
    teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id))
    to_student = db.relationship("StudentCourse", uselist=True, backref="to_course", lazy='dynamic')
    # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
    def __repr__(self):
        return 'Course:%s'% self.name

# 针对多对多。
# 创建一个中间表模型,进行关联[就是把原来2个模型之间的多对多转换成3个模型之间的一对多]
class StudentCourse(db.Model):
    __tablename__ = 'tb_student_course'
    id = db.Column(db.Integer, primary_key=True)
    sid = db.Column(db.Integer, db.ForeignKey(Student.id))
    cid = db.Column(db.Integer, db.ForeignKey(Course.id))
    created_time = db.Column(db.DateTime, nullable=True, )
    achievement = db.Column(db.Numeric(5,2), nullable=True )

    def __repr__(self):
        return 'Student:%s, Course:%s'% (self.to_student.name,self.to_course.name)

run.py,代码:

from flask import Flask,request,jsonify,render_template
from config import Config
from models2 import db,Student,Course,Teacher,StudentInfo

# 初始化
app = Flask(import_name=__name__,template_folder='templates')
app.config.from_object(Config)
db.init_app(app)  # 初始化数据库链接

@app.route(rule='/')
def index():
    """多对多[中间表作为模型创建使用]"""
    # 查询学生数据,关联查询课程
    student = Student.query.get(3)
    ret = student.to_course.all()
    for item in ret:
        print(item.to_course.name)

    return "ok"
if __name__ == '__main__':
    # 运行flask
    app.run(debug=True)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值