zoukankan      html  css  js  c++  java
  • 8-flask框架-数据的基本查询

    一、 常用的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后面,其他地方无法使用。

    2.1 get()

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

    Student.query.get()
    
    # # 根据主键获取一条数据
    # student = Student.query.get(4)
    # print(student)

    2.2 all()

    返回查询到的所有对象

    Student.query.all()
    
    # # 返回所有结果数据数据
    # student_list = Student.query.all()
    # print(student_list)

    2.3count()

    返回结果的数量

    # 返回结果的数量
    ret = Student.query.filter(Student.id<5).count()
    print(ret)

    2.4 first()

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

    Student.query.first()
    
    # # 返回第一个结果数据
    # first_student = Student.query.filter(Student.id<5).first()
    # print(first_student)

    2.5 filter条件查询

    支持各种运算符和查询方法或者模糊查询方法。

    # 模糊查询
    # 使用163邮箱的所有用户
    student_list = Student.query.filter(Student.email.endswith("@163.com")).all()
    print(student_list)
    
    # 姓名以"zh"开头的
    student_list = Student.query.filter(Student.name.startswith("zh")).all()
    print(student_list)
    
    # 名字中带有"a"字母的数据
    student_list = Student.query.filter(Student.name.contains("a")).all()
    print(student_list)
        
    # 也可以使用filter进行精确查找,
    # 则需要指定条件格式为: 模型.字段 比较运算符 值。
    # 运算符可以是: ==表示相等,!=不相等,> 表示大于  < 表示小于,>=大于等于,<=小于等于
    
    # 单条件比较
    student_list = Student.query.filter(Student.age>18).all()
    print(student_list)
    
    # 多条件比较
    # 要求多个条件都要满足
    student_list = Student.query.filter(Student.age>18, Student.sex==True).all()
    print(student_list)
    
        
    # 另一种写法的查询方式
    # db.session.query(Student) 相当于 Student.query
    # ret = db.session.query(Student).filte

    2.6、filter_by精确查询

    只支持字段的值是否相等这种条件

    # 单条件
    student_list = Student.query.filter_by(age=22).all()
    print(student_list)
    
    # 多条件
    student_list = Student.query.filter_by(age=22,sex=True).all()
    print(student_list)

    练习

    查询所有男生数据
    # ret = Student.query.filter(Student.sex==True).all()
    # ret = Student.query.filter_by(sex=True).all()
    
    查询id为4的学生[3种方式]
    # ret = Student.query.filter(Student.id==4).first()
    # ret = Student.query.get(4)
    # ret = Student.query.filter_by(id=4).first()
     
    查询年龄等于22的所有学生数据
    # ret = Student.query.filter_by(age=22).all()
    # ret = Student.query.filter(Student.age==22).all()
    
    查询name为liu的学生数据
    # ret = Student.query.filter(Student.name == "liu").all()
    # ret = Student.query.filter_by(name="liu").all()

    三、 多条件查询

    3.1 逻辑非

    返回名字不等于wang的所有数据

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

    not_ 相当于取反

    from sqlalchemy import not_
    Student.query.filter(not_(Student.name=='wang')).all()
    
    # # 查询年龄不等于22
    # student_list = Student.query.filter(Student.age != 22).all()
    # print(student_list)
    # student_list = Student.query.filter(not_(Student.age==22)).all()
    # print(student_list)

    3.2 逻辑与

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

    and_(条件1,条件2,....)  等价于  filter(条件1,条件2,.....)

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

    3.3 逻辑或

    from sqlalchemy import or_
    Student.query.filter(or_(Student.name!='wang',Student.email.endswith('163.com'))).all()
    
    # # 查询性别为True,或者年龄大于18
    # sex = 1 or age > 18
    # student_list = Student.query.filter(
    #     or_(
    #         Student.sex==True,
    #         Student.age>18
    #     )
    # ).all()
    # print(student_list)
    
    
    # 复合条件的查询情况
    # 查询18岁的女生或者22岁的男生
    # (age=18 and sex=0) or (age = 22 and sex=1)
    # student_list = Student.query.filter(
    #     or_(
    #         and_(Student.age==18, Student.sex==False),
    #         and_(Student.age==22, Student.sex==True),
    #     )
    # ).all()
    
    # print( student_list )

    3.4 、in_范围查询

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

    3.5 order_by 排序

    # 倒序[值从大到小]
    student_list = Student.query.order_by(Student.id.desc()).all()
    # 升序[值从小到大]
    student_list = Student.query.order_by(Student.id.asc()).all()
    
    # 多字段排序[第一个字段值一样时,比较第二个字段,进行排序]
    student_list = Student.query.order_by(Student.age.desc(), Student.id.asc() ).all()
    print(student_list)

    3.6 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.7 offset和limit

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

    """限制结果数量"""
    student_list = Student.query.limit(2).all()
    print(student_list)
    
     """结果返回的开始下标位置,从0开始"""
    student_list = Student.query.offset(0).limit(2).all()
    print(student_list)
    student_list = Student.query.limit(2).offset(2).all()
    print(student_list)
        

     四、分页器

     4.1 分页器常用属性

    @app.route("/")
    def index():
        # 分页器
        page = int(request.args.get("page",1))
        # page 当前页码  per_page:每页显示的数据个数
        paginate = Student.query.paginate(page=page,per_page=3)
    
        print(paginate.items) # 当前页显示的数据项
        print(paginate.pages) # 总页码
        print(paginate.page)  # 当前页码
        print(paginate.has_prev) # 是否有上一页
        print(paginate.prev_num) # 上一页页码
        print(paginate.prev)     # 上一页的分页器对象
        print(paginate.has_next) # 是否有下一页
        print(paginate.next_num) # 下一页页码
        print(paginate.next)     # 下一页的分页器对象
    
        data = {
            "error":0,
            "errmsg": "ok",
            "data": {
                "items": [data.to_dict for data in paginate.items],
                "pages": paginate.pages,
                "page": paginate.page,
                "has_prev": paginate.has_prev,
                "prev_num": paginate.prev_num,
                "has_next": paginate.has_next,
                "next_num": paginate.next_num,
            }
        }
    
        return data

     4.2 前后端不分离实例

      1 from flask import Flask,render_template,request
      2 from flask_sqlalchemy import SQLAlchemy
      3 
      4 app = Flask(__name__)
      5 
      6 class Config(object):
      7     DEBUG = True
      8     # 数据库连接配置
      9     # SQLALCHEMY_DATABASE_URI = "数据库类型://数据库账号:密码@数据库地址:端口/数据库名称?charset=utf8mb4"
     10     SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4"
     11     # 动态追踪修改设置,如未设置只会提示警告
     12     SQLALCHEMY_TRACK_MODIFICATIONS = True
     13     # 查询时会显示原始SQL语句
     14     SQLALCHEMY_ECHO = True
     15 
     16 app.config.from_object(Config)
     17 
     18 
     19 """模型类定义"""
     20 db = SQLAlchemy(app=app)
     21 # 等同于
     22 # db = SQLAlchemy()
     23 # db.init_app(app)
     24 
     25 class Student(db.Model):
     26     """学生信息模型"""
     27     # 声明与当前模型绑定的数据表名称
     28     __tablename__ = "db_students"
     29     # 字段定义
     30     """
     31     create table db_student(
     32       id int primary key auto_increment comment="主键",
     33       name varchar(15) comment="姓名",
     34     )
     35     """
     36     id = db.Column(db.Integer, primary_key=True,comment="主键")
     37     name = db.Column(db.String(15), comment="姓名")
     38     age = db.Column(db.SmallInteger, comment="年龄")
     39     sex = db.Column(db.Boolean, default=True, comment="性别")
     40     email = db.Column(db.String(128), unique=True, comment="邮箱地址")
     41     money = db.Column(db.Numeric(10,2), default=0.0, comment="钱包")
     42 
     43     def __repr__(self):
     44         return f"{self.name}<Student>"
     45 
     46     @classmethod
     47     def add(cls):
     48         student = cls(name="小明", sex=True, age=17, email="123456@qq.com", money=100)
     49         db.session.add(student)
     50         db.session.commit()
     51         return student
     52 
     53     @property
     54     def to_dict(self):
     55         """把对象转化成字典"""
     56         return {
     57             "id": self.id,
     58             "name": self.name,
     59             "age": self.age,
     60             "sex": self.sex,
     61             "email": self.email,
     62             "money": float("%.2f" % self.money),
     63         }
     64 
     65 # 所有的模型必须直接或间接继承于db.Model
     66 class Course(db.Model):
     67     """课程数据模型"""
     68     __tablename__ = "db_course"
     69     id = db.Column(db.Integer, primary_key=True, comment="主键")
     70     name = db.Column(db.String(64), unique=True, comment="课程")
     71     price = db.Column(db.Numeric(7, 2))
     72     # repr()方法类似于django的__str__,用于打印模型对象时显示的字符串信息
     73     def __repr__(self):
     74         return f'{self.name}<Course>'
     75 
     76 class Teacher(db.Model):
     77     """老师数据模型"""
     78     __tablename__ = "db_teacher"
     79     id = db.Column(db.Integer, primary_key=True, comment="主键")
     80     name = db.Column(db.String(64), unique=True, comment="姓名")
     81     option = db.Column(db.Enum("讲师", "助教", "班主任"), default="讲师")
     82 
     83     def __repr__(self):
     84         return f"{self.name}< Teacher >"
     85 
     86 @app.route("/")
     87 def index():
     88     # 分页器
     89     page = int(request.args.get("page",1)) # 页码
     90     size = int(request.args.get("size",5)) # 每一页数据量
     91     pagination = Student.query.paginate(page=page,per_page=size)
     92     data = {}
     93     data["pagination"] = pagination
     94     return render_template("list.html",**data)
     95 
     96 
     97 if __name__ == '__main__':
     98     with app.app_context():
     99         # 检测数据库中是否存在和模型匹配的数据表。
    100         # 如果没有,则根据模型转换的建表语句进行建表。
    101         # 如果找到,则不会进行额外处理
    102 
    103         db.create_all()
    104     app.run(debug=True)
    服务器端

    同一级目录下  templates/list.html

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6     <style>
     7     .page a,.page span{
     8         padding: 2px 6px;
     9         color: #fff;
    10         background: #6666ff;
    11         text-decoration: none;
    12     }
    13     .page span{
    14         color: #fff;
    15         background: orange;
    16     }
    17 
    18     </style>
    19 </head>
    20 <body>
    21     <table border="1" align="center" width="600">
    22         <tr>
    23            <th>ID</th>
    24            <th>age</th>
    25            <th>name</th>
    26            <th>sex</th>
    27            <th>money</th>
    28         </tr>
    29         {% for student in pagination.items %}
    30         <tr>
    31            <td>{{ student.id }}</td>
    32            <td>{{ student.age }}</td>
    33            <td>{{ student.name }}</td>
    34            <td>{{ "男" if student.sex else "女" }}</td>
    35            <td>{{ student.money }}</td>
    36         </tr>
    37         {% endfor %}
    38         <tr align="center">
    39             <td colspan="5" class="page">
    40                 {% if pagination.has_prev %}
    41                 <a href="?page=1">首  页</a>
    42                 <a href="?page={{ pagination.page-1 }}">上一页</a>
    43                 <a href="?page={{ pagination.page-1 }}">{{ pagination.page-1 }}</a>
    44                 {% endif %}
    45                 <span>{{ pagination.page }}</span>
    46                 {% if pagination.has_next %}
    47                 <a href="?page={{ pagination.page+1 }}">{{ pagination.page+1 }}</a>
    48                 <a href="?page={{ pagination.page+1 }}">下一页</a>
    49                 <a href="?page={{ pagination.pages }}">尾  页</a>
    50                 {% endif %}
    51             </td>
    52         </tr>
    53     </table>
    54 </body>
    55 </html>
    前端代码

    五、分组查询

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

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

    from sqlalchemy import func

    函数名说明 
    func.count 统计总数  
    func.avg 平均值  
    func.min 最小值  
    func.max 最大值  
    func.sum  

    代码:

    # 查询当前所有男生女生的数量
    # ret = db.session.query(Student.sex,func.count(Student.id)).group_by(Student.sex).all()
    # print(ret)
    
    # 查看当前学生中各个年龄段的学生人数
    # ret = db.session.query(Student.age, func.count(Student.id)).group_by(Student.age).all()
    # print(ret)
    
    # 查看当前男生女生的平均年龄
    # ret = db.session.query(Student.sex, func.avg(Student.age)).group_by(Student.sex).all()
    # ret = [{"sex":"男" if item[0] else "女","age":float(item[1])} for item in ret]
    # print(ret)
    
    # 分组后的过滤操作 having
    # 在所有学生中,找出各个年龄中拥有最多钱的同学,并在这些同学里面筛选出money > 2000的数据
    subquery = func.max(Student.money)
    ret = db.session.query(Student.age, subquery).group_by(Student.age).having(subquery > 2000).all()
    print(ret) # [(18, Decimal('1000.00')), (22, Decimal('26000.00')), (23, Decimal('1998.00'))]

    六、执行原生SQL语句

    # # 查询多条数据
    # ret = db.session.execute("select * from db_students").fetchall()
    # # 查询一条数据
    # ret = db.session.execute("select * from db_students").fetchone()
    #
    # # 添加/删除/更新
    # db.session.execute("UPDATE db_students SET money=(db_students.money + %s) WHERE db_students.age = %s" % (200, 22))
    # db.session.commit()
    
    # db.session.execute("insert db_students (name,age,sex,email,money) select name,age,sex,concat(now(),email),money from db_students")
    # db.session.commit()
    return "ok"
  • 相关阅读:
    2.4 自给自足的脚本:位于第一行的#!
    2.3 一个简单的脚本
    2.2 为什么要使用Shell脚本
    JSON 字符串 与 java 对象的转换
    ajax异步提交文件
    jquery选择器
    发现前端框架 bui-min.js
    学习hsf
    Git详解
    java学习材料
  • 原文地址:https://www.cnblogs.com/yj0405/p/14824592.html
Copyright © 2011-2022 走看看