• Python-12-MySQL & sqlalchemy ORM


    MySQL

    MySQL相关文章这里不在赘述,想了解的点击下面的链接:

    >> MySQL安装

    >> 数据库介绍 && MySQL基本使用

    >> MySQL使用(一)

    >> MySQL使用(二)

    Python操作MySQL

    本篇对于Python操作MySQL主要使用两种方式:

    • 原生模块 pymsql
    • ORM框架 SQLAchemy

    pymysql

    pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同。

    下载安装

    pip3 install pymysql
    

    使用操作

    1、执行SQL

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
      
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
    # 创建游标
    cursor = conn.cursor()
      
    # 执行SQL,并返回收影响行数
    effect_row = cursor.execute("update hosts set host = '1.1.1.2'")
      
    # 执行SQL,并返回受影响行数
    #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,))
      
    # 执行SQL,并返回受影响行数
    #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)])
      
      
    # 提交,不然无法保存新建或者修改的数据
    conn.commit()
      
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    

    2、获取新创建数据自增ID

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
      
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
    cursor = conn.cursor()
    cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)])
    conn.commit()
    cursor.close()
    conn.close()
      
    # 获取最新自增ID
    new_id = cursor.lastrowid
    

    3、获取查询数据

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
      
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
    cursor = conn.cursor()
    cursor.execute("select * from hosts")
      
    # 获取第一行数据
    row_1 = cursor.fetchone()
      
    # 获取前n行数据
    # row_2 = cursor.fetchmany(3)
    # 获取所有数据
    # row_3 = cursor.fetchall()
      
    conn.commit()
    cursor.close()
    conn.close()
    

    注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:

    • cursor.scroll(1,mode='relative') # 相对当前位置移动
    • cursor.scroll(2,mode='absolute') # 相对绝对位置移动

    4、fetch数据类型

    关于默认获取的数据是元组类型,如果想要或者字典类型的数据,即:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
      
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
      
    # 游标设置为字典类型
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    r = cursor.execute("call p1()")
      
    result = cursor.fetchone()
      
    conn.commit()
    cursor.close()
    conn.close()
    

    ORM && sqlalchemy

    ORM介绍

    ORM英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过ORM将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用SQL语言。

    ORM的优点:

    1. 隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
    2. ORM使我们构造固化数据结构变得简单易行。

    ORM的缺点:

    1. 无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。

    sqlalchemy

    SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果点击这里了解主要用户列表

    ORM

    SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:

    # MySQL-Python
        mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
       
    # pymysql
        mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
       
    # MySQL-Connector
        mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
       
    # cx_Oracle
        oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
       
    更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
    

    sqlalchemy 安装

    pip3 install SQLAlchemy
    

    sqlalchemy 操作数据

    使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL。

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    import sqlalchemy
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column,Integer,String
    
    engine = create_engine("mysql+pymysql://root:123456@192.168.92.201/test?charset=utf8",encoding='utf-8',echo=True)
    
    Base = declarative_base()  # 生成ORM基类
    
    class User(Base):
        __tablename__='users'  # 表名
        id = Column(Integer,primary_key=True)
        name = Column(String(32))
        password = Column(String(64))
    
        def __repr__(self):  # 让返回的数据不直接是对象,变得可读
            return "<User(name='%s',password='%s')>" % (self.name,self.password)
    
    # 创建表结构:寻找Base的所有子类,按照子类的结构在数据库中生成对应的数据表信息
    # Base.metadata.create_all(engine)
    
    Session_class = sessionmaker(bind=engine)
    session = Session_class()
    
    ################### 插入一条数据 ###################
    data1 = User(name="Jack",password="123")
    session.add(data1)
    session.commit()
    
    ################### 插入多条数据 ###################
    session.add_all([
        User(ame="David",password="333")
        User(ame="Lily",password="666")
    ])
    session.commit()
    
    ##################### 查询数据 #####################
    my_user = session.query(User).filter_by(name="David").first()
    print (my_user)
    # 你可以看到输出结果是 <User(name='David',password='123')> ,如果不加__repr__,返回的数据直接是对象。
    
    ### 其他查询姿势:
    my_user = session.query(User).filter(User.id>0).filter(User.id<7).all()  # 多条件查询,相当于 user.id >1 AND user.id <7
    
    my_user = session.query(User).filter(User.name.in_(['David','SB'])).all()  # select tables in ...
    
    my_user = session.query(User.name.label('name_label')).all()  # ???
    
    my_user = session.query(User).order_by(User.id).all()   # 排序
    
    my_user = session.query(User).order_by(User.id)[1:3]   # 结果从1~3顺序显示
    
    my_user = session.query(User).filter(User.name.like("Da%")).count()  # like匹配 && 统计
    
    ### 分组查询:
    from sqlalchemy import func
    my_user = session.query(func.count(User.name),User.name).group_by(User.name).all()
    # 相当于SQL为:
    SELECT count(user.name) AS count_1, user.name AS user_name FROM user GROUP BY user.name;
    # 输出结果为:
    [(1, 'Jack'), (2, 'Rain')]
    
    print (my_user)
    session.commit()
    
    ##################### 修改数据 #####################
    session.query(User).filter(User.name=="David").update({'password':4848})
    session.commit()
    # 上述方法可以修改数据,还有一种方法,当你查询出来数据的时候,也可以直接修改,看下面步骤:
    my_user = session.query(User).filter_by(name="David").first()
    my_user.name = "SB"
    session.commit() 
    
    ##################### 删除数据 #####################
    session.query(User).filter(User.name=="David").delete
    
    ####################### 回滚 #######################
    session.rollback()
    # sqlalchemy操作默认就是事务,增删改balabala..只要没commit,随时可以rollback...
    
    

    注:SQLAlchemy无法修改表结构,如果需要可以使用SQLAlchemy开发者开源的另外一个软件Alembic来完成。

    外键关联

    我们创建一个addresses表,跟上面创建的users表关联

    from sqlalchemy import ForeignKey
    from sqlalchemy.orm import relationship
     
    class Address(Base):
        __tablename__ = 'addresses'
        id = Column(Integer, primary_key=True)
        email_address = Column(String(32), nullable=False)
        user_id = Column(Integer, ForeignKey('users.id'))
     
        user = relationship("User", backref="addresses") # 允许你在user表里通过backref字段反向查出所有它在addresses表里的关联项
     
        def __repr__(self):
            return "<Address(email_address='%s')>" % self.email_address
    

    表创建好后,我们这样来反查试试

    obj = Session.query(User).first()
    for i in obj.addresses: #通过user对象反查关联的addresses记录
        print(i)
     
    addr_obj = Session.query(Address).first()
    print(addr_obj.users.name)  #在addr_obj里直接查关联的users表
    

    创建关联对象

    obj = Session.query(User).filter(User.name=='David').all()[0]
    print(obj.addresses)
     
    obj.addresses = [Address(email_address="xx@jd.com"), #添加关联对象
                     Address(email_address="oo@jd.com")]
     
    session.commit()
    

    多外键关联

    下表中,Customer表有2个字段都关联了Address表

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    import sqlalchemy
    from sqlalchemy import create_engine
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column,Integer,String,ForeignKey
    from sqlalchemy.orm import relationship,sessionmaker
    from sqlalchemy import ForeignKey
    
    engine = create_engine("mysql+pymysql://root:123456@192.168.92.201/test?charset=utf8",
                           encoding='utf-8',echo=True)
    
    Base = declarative_base()  # 生成ORM基类
    
    class Customer(Base):
        __tablename__ = 'customer'
        id = Column(Integer, primary_key=True)
        name = Column(String(64))
        billing_address_id = Column(Integer, ForeignKey("new_address.id"))
        shipping_address_id = Column(Integer, ForeignKey("new_address.id"))
    
        billing_address = relationship("Address",foreign_keys=[billing_address_id])     # 此处添加foreign_keys来执行外键和哪个字段对应
        shipping_address = relationship("Address",foreign_keys=[shipping_address_id])
    
    class Address(Base):
        __tablename__ = 'new_address'
        id = Column(Integer, primary_key=True)
        street = Column(String(64))
        city = Column(String(64))
        state = Column(String(64))
    
    # Base.metadata.create_all(engine)
    
    Session_class = sessionmaker(bind=engine)
    session = Session_class()
    
    # 添加几个数据试试!!
    addr1 = Address(street="fengtai",city="beijing",state="china")
    addr2 = Address(street="haidian",city="beijing",state="china")
    addr3 = Address(street="fangshan",city="beijing",state="china")
    
    c1 = Customer(name="user1",billing_address_id="2",shipping_address_id="3")
    c2 = Customer(name="user2",billing_address_id="1",shipping_address_id="3")
    c3 = Customer(name="user3",billing_address_id="3",shipping_address_id="3")
    
    session.add_all([addr1,addr2,addr3,c1,c2,c3])
    session.commit()
    

    多对多关系

    现在来设计一个能描述“图书”与“作者”的关系的表结构,需求是:

    1. 一本书可以有好几个作者一起出版
    2. 一个作者可以写好几本书

    此时,我们可以再搞出一张中间表,来关联书名和作者。

    下面我们通过book_m2m_author表完成了book表和author表之前的多对多关联

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey,engine
    from sqlalchemy.orm import relationship
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    
    engine = create_engine("mysql+pymysql://root:123456@192.168.92.201/test?charset=utf8",
                           encoding='utf-8',echo=True)
    
    Base = declarative_base()
    
    # 创建一个表来让sqlalchemy关联authors表和books表
    book_m2m_author = Table('book_m2m_author', Base.metadata,
                            Column('book_id',Integer,ForeignKey('books.id')),
                            Column('author_id',Integer,ForeignKey('authors.id')),
                            )
    
    class Book(Base):
        __tablename__ = 'books'
        id = Column(Integer,primary_key=True)
        name = Column(String(64))
        pub_date = Column(DATE)
        authors = relationship('Author',secondary=book_m2m_author,backref='books')
    
        def __repr__(self):
            return self.name
    
    class Author(Base):
        __tablename__ = 'authors'
        id = Column(Integer, primary_key=True)
        name = Column(String(32))
    
        def __repr__(self):
            return self.name
    
    # Base.metadata.create_all(engine)
    Session_class = sessionmaker(bind=engine)    #创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
    s = Session_class()   #生成session实例
    
    # 插入数据
    b1 = Book(name="book1",pub_date="2016-05-08")
    b2 = Book(name="book2",pub_date="2017-06-08")
    b3 = Book(name="book3",pub_date="2018-07-08")
    b4 = Book(name="book4",pub_date="2019-08-08")
    b5 = Book(name="book5",pub_date="2020-08-08")
    
    a1 = Author(name="Alex")
    a2 = Author(name="Jack")
    a3 = Author(name="Rain")
    a4 = Author(name="David")
    
    b1.authors = [a1,a2]
    b2.authors = [a1,a2,a3]
    b5.authors = [a4]
    
    s.add_all([b1,b2,b3,b4,b5,a1,a2,a3,a4])
    s.commit()
    

    此时,我们去用orm查一下数据

    print('--------通过书表查关联的作者---------')
     
    book_obj = s.query(Book).filter_by(name="book1").first()
    print(book_obj.name, book_obj.authors)
     
    print('--------通过作者表查关联的书---------')
    author_obj =s.query(Author).filter_by(name="David").first()
    print(author_obj.name , author_obj.books)
    s.commit()
    

    输出如下

    --------通过书表查关联的作者---------
    book1 [David, Jack]
    --------通过作者表查关联的书---------
    Alex [book3, book4]
    

    这就实现了多对多关系啦!

    多对多删除

    删除数据时不用管boo_m2m_authors , sqlalchemy会自动帮你把对应的数据删除

    通过书删除作者

    author_obj =s.query(Author).filter_by(name="Jack").first()
     
    book_obj = s.query(Book).filter_by(name="book2").first()
     
    book_obj.authors.remove(author_obj) #从一本书里删除一个作者
    s.commit()
    

    直接删除作者

    删除作者时,会把这个作者跟所有书的关联关系数据也自动删除

    author_obj =s.query(Author).filter_by(name="David").first()
    # print(author_obj.name , author_obj.books)
    s.delete(author_obj)
    s.commit()
    
  • 相关阅读:
    Linux中find命令用法全汇总,看完就没有不会用的!
    ubuntu16.04 通过命令,修改屏幕分辨率
    Linux下如何查看哪些进程占用的CPU内存资源最多
    shell脚本 在后台执行de 命令 >> 文件 2>&1 将标准输出与错误输出共同写入到文件中(追加到原有内容的后面)
    ef linq 访问视图返回结果重复
    asp.net core web 本地iis开发
    jQuery控制TR显示隐藏
    mvc EF 从数据库更新实体,添加视图实体时添加不上的问题
    无法确定依赖操作的有效顺序。由于外键约束、模型要求或存储生成的值,因此可能存在依赖关系
    还原差异备份——因为没有文件可用于前滚
  • 原文地址:https://www.cnblogs.com/huyuedong/p/6006005.html
Copyright © 2020-2023  润新知