zoukankan      html  css  js  c++  java
  • flask之数据库的交互

    一:关系型数据库 mysql

      Flask-SQLAlchemy管理关系型数据库。

      mysql数据库引擎:url : mysql://username:passowrd@hostname/database

      安装相关依赖包

        pip install flask-sqlalchemy

        pip install flask-mysqldb  如果使用mysql数据库需要安装这个依赖包

      数据库连接配置

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest"  # 配置数据库的链接
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True  # 请求结束后自动提交数据库的变动
    app.config['SQLALCHEMY_ECHO'] = True # 执行后显示原始sql语句
    
    db = SQLAlchemy(app)
    
    @app.route("/user")
    def user():
        pass
    
    if __name__ == '__main__':
        app.run()

    二:数据库模型 orm

      object-relationship-map 对象关系映射,简答说:就是通过创建实例对象==相当于在数据库中映射了一张表。

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    app = Flask(__name__)
    app.config["SQLALCHEMY_DATABASE"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest"
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
    app.config['SQLALCHEMY_ECHO'] = True
    
    db = SQLAlchemy(app)
    
    @app.route("/user")
    def user():
        pass
    
    
    # 定义对象
    class Role(db.Model):
        # 类变量定义了数据库中的表名。如果没有指定,会已类的名称小写为表名,也就是role
        __tablename__ = "roles"
        id = db.Column(db.Integer,primary_key=True)  # create table roles(id int(64) primary key, name varchar(64) unique);
        name = db.Column(db.String(64),unique=True)  # desc roles; 
        def __repr__(self):
            return "<Role %s>" % self.name
    
    
    class User(db.Model):
        __tablename__ = "users"
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(64), unique=True,index=True)
        def __repr__(self):
            return "<User %s>" % self.username
    
    if __name__ == '__main__':
        app.run()

       外键和关联的创建

    # 定义对象
    class Role(db.Model):
        # 类变量定义了数据库中的表名。如果没有指定,会已类的名称小写为表名,也就是role
        __tablename__ = "roles"
        id = db.Column(db.Integer,primary_key=True)
        name = db.Column(db.String(64),unique=True)
        us = db.relationship("User",backref="role")  # us这个字段,关联了User类(要写类名):backref="role"表明User类中可以反向引用role对象。
        
        def __repr__(self):
            return "<Role %s>" % self.name
    
    
    class User(db.Model):
        __tablename__ = "users"
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(64), unique=True,index=True)
        role_id = db.Column(db.Integer,db.ForeignKey("roles.id"))  # role_id 是关联了roles表的id字段。
    
        def __repr__(self):
            return "<User %s>" % self.username

    # 一对多的关系:一个role可以对应多个user用户。

      插入数据:

      报错:'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '

    from flask import Flask
    from flask.ext.sqlalchemy import SQLAlchemy
    app = Flask(__name__)
    db = SQLAlchemy(app) # 错误一:db在app.config之后设置,应该为之前设置。
    app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@127.0.0.1:3306/flaskmysqltest" # 错误二:SQLALCHEMY_DATABASE_URI不是URL
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = False   #SQLALCHEMY_COMMIT_ON_TEARDOWN 键,将其设为True时,每次请求结束后都会自动提交数据库中的变动
    app.config['SQLALCHEMY_ECHO'] = True
    if __name__ == '__main__':
        app.run(debug=True)
        db.create_all()  # 执行所有的类,进行建表。roles 和 user表创建成功。
        r1 = Role(name="admin") # 给roles表中插入数据
        db.session.add(r1)
        db.session.commit()




       删除所有的表

    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 将这个从False改为True,请求后数据库自动提交数据变动,要不然删除不成功

    if __name__ == '__main__':
      app.run(debug=True)
      db.drop_all() # 删除所有的表
      db.session.commit() 

     再次创建所有表

    if __name__ == '__main__':
        app.run(debug=True)
        db.create_all()
        db.session.commit()

     再次执行删除所有的表

    if __name__ == '__main__':
        app.run(debug=True)
        db.drop_all()
        db.session.commit()
    
    但是结果:表依然没有删除掉

    到底是什么原因呢?

    解决办法:重新启动flask框架,后再次执行后,才能实现删除表。

    注意:重新建表和插入数据,也得重启flask框架才能生效。

    if __name__ == '__main__':
        app.run(debug=True)
        db.create_all()
        r1 = Role("admin")
        r2 = Role("no_admin")
        db.session.add_all([r1, r2])
        db.session.commit()
    问题:只执行了创表语句,插入语句没有执行,什么原因?是不是因为要db.create_all()也要用db.session.commit()

    if __name__ == '__main__':
        app.run(debug=True)
        db.create_all()
        db.session.commit()
        r1 = Role(name="admin")
        r2 = Role(name="noadmin")
        db.session.add_all(r1,r2)
        db.session.commit()
    更改后:依然只能执行建表语句,插入数据不成功,到底是什么原因呢?原因是列表 db.session.add_all([r1,r2])没有加列表。然后还是要重启,框架插入语句才能被查询到。

    全部的问题:框架运行到app.run()就阻塞了,当关闭框架时,会执行到,后面的语句,语句才生效,我太笨了。

    继续连续两次ctrl+s框架自动刷新,报错:

    sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1062, "Duplicate entry 'aaaaaa' for key 'name'") [SQL: 'INSERT INTO title (name) VALUES (%(name)s)'] [parameters: {'name': 'aaaaaa'}]
    原因是:username设置的 unique=True,再次插入遇到重复的名字就报错了。

    三:sqlalchemy语句的操作

    实例:通过python shell 的方式操作数据库

      终端中打开 ipython

      输入 from mysql_tesst impoty User,Role 报错:

      Non-ASCII character 'xe7' in file mysql_test.py on line 16, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details。

      原因是:ipython 版本默认使用的是 Python2.7.12 在python2的版本中,程序中有中文或者中文注释,第一行必须加上,# encoding: utf-8。

      pip3 install ipython 将ipython的版本换成python3的版本就行了

     下面将使用python shell的ipython3操作数据库

      1.表中插入数据

    from mysql_test import User,db
    
    r1 = Role(name="Admin2")  # 1.模型定义:
    
    print(r1.id)  # None
    
    db.session.add(r1) # 2.增加模型到数据库的操作层
    
    db.session.commit() # 3.将模型转换为mysql的原生语句,进行插入数据。
    
    print(r1.id) # 3  # 获取表中某个字段,直接通过实例属性r1.id进行取值,方便 select id from roles where name="Admin2" 



    # 为什么id不是按照顺序排列的,
    # 原因是:id字段设置时候,只是设置了为primary key并没有设置为自增类型,auto_increment

       2. 修改表中的字段信息

    还是在上次的shell基础上进行操作
    
    要求:将表中的Admin2字典修改为admin2
    
    r1.name = "admin2"  # 通过赋值的方式修改表中name的值
    
    db.session.add(r1)  
    
    db.session.commit()
    
    print(r1.name)  # admin2


       3. 删除表的数据

    # 接着上面的shell
    
    db.session.delete(r1)
    
    db.session.commit()


       4.查询数据:sqlalchemy提供了 query对象进行数据查询

    Role.query.all()  # query.all()表示查询所有的数据
    
    [<Role admin>, <Role noadmin>]  查询操作,没有修改表的结构,因此不需要session.commit():返回的是查询的对象

    返回的样式为什么是这样呢?
    def __repr__(self):
    return "<Role %s>" % self.username

    原因是:模型类中定义的这个函数进行决定的。

       查询数据query配合过滤器filter可以更加准确的查询所需要的数据

    User.query.filter_by(username="张惠妹").all()  
    
    [<User 张惠妹>]  # 显示的样式同上

    
    

       查询users中用户id大于2的所有用户

    User.query.filter_by(id>1).all()  # 原因filter_by只能用于等值过滤
    User.query.filter(id>1).all() # 原因:id 应该改为User.id 表示是这个表的id字段。
    
    # 以上两种方式的查询均报错:
    unorderable types: builtin_function_or_method() > int() 

    扩展:filter()中条件的写法

      users = User.query.filter(条件1).first()
      条件的写法:
      User.name.endswith('g')
      User.name.startswith('g')
      User.name.containswith('g')
      User.name == “laowang”
      User.age == 12
      User.age > 12
      User.id.in_(列表)

       查询users中的id大于2且名字为张学良的用户

    User.query.filter(User.id>1 ,User.username=="张学良").all() 
    
    [<User 张学良>]

    扩展:filter()中多条件查询的写法

      users = User.query.filter(条件1,条件2,条件3).first()
      users = User.query.filter(or_(条件1,条件2,条件3)).first()
      users = User.query.filter(not_(条件1)).all()

       其他的过滤条件

    排序 
        User.query.order_by(字段.哪一种排序).all()
        User.query.order_by(User.name.desc()).all()
    
    
    分页
        aa = User.query.paginate(第几页,每一页几条)
        aa.pages
        aa.page
        aa.items

      执行函数

    3.视图中操作数据库

      # todo

      

  • 相关阅读:
    sql 语句总结
    linux 操作命令
    elk 相关问题总结
    windows 下命令总结
    spring 生态的区别
    电脑基本常识 cpu的认识
    git 命令总结
    reques 和session
    linux centos7 安装docker
    get和post请求
  • 原文地址:https://www.cnblogs.com/meloncodezhang/p/11733751.html
Copyright © 2011-2022 走看看