zoukankan      html  css  js  c++  java
  • SQLAlchemy-ORM

    ORM技术简介

    ORM:及Object-Relational Mapping,对象关系映射,把关系数据库的表结构映射到对象上。
    我们先来可能一个例子:
    如果我们从数据库查出来几条数据,需要你在python中表示出来,如果你没有接触过ORM技术,你或许会使用下面的形式来存储这个数据:

    [
        (1, "yangjian"),
        (2, "chengdu"),
        (3, "hello"),
    ]

    如果你想知道表结构是什么样的,是不是就费劲了,如果你想快速得出其中的元素,就需要听听ORM的思想了。

    数据库中每次查出来的数据都用一个类表示,这个类的属性和数据库中表的字段一一对应。多条数据,就是一个list,每一行数据都是一个类来表示,如下所示:

    class User(object):
        def __init__(self, id, name):
            self.id = id
            self.name = name
    [
        User(1, "yangjian"),
        User(2, "chengdu"),
        User(3, "hello"),
    ]

    当我们需要获得id,或者name的时候,只需要通过循环获取到对象,直接通过user1.id或者user1.name就可以获取到id和name的属性。并且使得数据的存取非常的规范,这样ORM架构应用而生。

    SQLAlchemy

    Python中最有名的ORM架构就是SQLAlchemy,我们主要就是来学习SQLAlchemy的使用。

    安装环境

    pip install SQLAlchemy

    安装mysql

    yum install mysql-server mysql
    service mysqld restart
    sysctmctl restart mysql.service

    创建数据库并授权

    create database sqlalchemy;
    GRANT ALL PRIVILEGES ON *.* TO 'yangjian'@'%' IDENTIFIED BY '123456';

    初始化连接

    from sqlalchemy import create_engine
    engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy', echo=True)

    echo参数为True时,会显示每条执行的SQL语句,可以关闭。
    create_engine()返回一个Engine的实例,并且它表示通过数据库语法处理细节的核心接口,在这种情况下,数据库语法将会被解释成python的类方法。
    mysql://yangjian:123456@192.168.48.131/sqlalchemy
    mysql+pymysql: 指定是哪种数据库连接,在python3中不写成mysql+pymysql会报找不到MySQLdb模块的错误
    yangjina: 数据库用户名
    123456: 数据库用户对应的密码
    192.168.48.131: 数据库的ip
    sqlalchemy: 数据库需要连接哪个库的名字

    创建表格

    有以下两种方式创建数据库表:

    1. 主要是通过sql语句来创建表格

    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    
    sql = '''create table student(
        id int not null primary key,
        name varchar(50),
        age int,
        address varchar(100));
    '''
    
    engine = create_engine('mysql://yangjian:123456@192.168.48.131/sqlalchemy')
    conn = engine.connect()
    conn.execute(sql)
    engine.connect() #表示获取到数据库连接。类似我们在MySQLdb中游标cursor的作用。

    2. 通过ORM方式创建表格

    from sqlalchemy import Column
    from sqlalchemy import Integer
    from sqlalchemy import MetaData
    from sqlalchemy import String
    from sqlalchemy import Table
    from sqlalchemy import create_engine
    from sqlalchemy.ext.declarative import declarative_base
    
    engine = create_engine('mysql://yangjian:123456@192.168.48.131/sqlalchemy')
    metadata = MetaData(engine)
    user = Table('user', metadata,
                 Column('id', Integer, primary_key=True),
                 Column('name', String(20)),
                 Column('fullname', String(40))
                 )
    metadata.create_all(engine)
    conn = engine.connect()
    print(conn)

    MetaData类主要用于保存表结构,连接字符串等数据,是一个多表共享的对象
    metadata = MetaData(engine) 绑定一个数据源的metadata
    metadata.create_all(engine) 是来创建表,这个操作是安全的操作,会先判断表是否存在。
    Table类
    构造函数:
    Table.__init__(self, name, metadata,*args, **kwargs)
    name 表名
    metadata 共享的元数据
    *args Column 是列定义

    下面是可变参数 **kwargs 定义
    schema 此表的结构名称,默认None
    autoload 自动从现有表中读入表结构,默认False
    autoload_with 从其他engine读取结构,默认None

    Column类

    构造函数

    Column.__init__(self,  name,  type_,  *args,  **kwargs)

    1、name 列名
    2、type_ 类型,更多类型 sqlalchemy.types
    3、*args Constraint(约束),  ForeignKey(外键),  ColumnDefault(默认), Sequenceobjects(序列)定义
    4、key 列名的别名,默认None
    下面是可变参数 **kwargs
    5、primary_key 如果为True,则是主键
    6、nullable 是否可为Null,默认是True
    7、default 默认值,默认是None
    8、index 是否是索引,默认是True
    9、unique 是否唯一键,默认是False
    10、onupdate 指定一个更新时候的值,这个操作是定义在SQLAlchemy中,不是在数据库里的,当更新一条数据时设置,大部分用于updateTime这类字段
    11、autoincrement 设置为整型自动增长,只有没有默认值,并且是Integer类型,默认是True
    12、quote 如果列明是关键字,则强制转义,默认False

    创建会话

    说到数据库,就离不开Session。Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。
    在Sqlalchemy中,数据库的查询操作是通过Query对象来实现的。而Session提供了创建Query对象的接口。
    Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射,是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。
    要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。
    当然Session最重要的功能还是实现原子操作。
    ORM通过session与数据库建立连接进行通信,如下所示:

    from sqlalchemy.orm import sessionmaker
    
    DBSession = sessionmaker(bind=engine)
    session = DBSession()
    
    # 通过sessionmake方法创建一个Session工厂,然后在调用工厂的方法来实例化一个Session对象。

    添加数据

    from sqlalchemy import Column
    from sqlalchemy import Integer
    from sqlalchemy import String
    from sqlalchemy import create_engine
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import sessionmaker
    
    Base = declarative_base()
    class Student(Base):
        __tablename__ = 'student'
        id = Column(Integer, primary_key=True)
        name = Column(String(50))
        age = Column(Integer)
        address = Column(String(100))
    
    engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy')
    DBSession = sessionmaker(bind=engine)
    session = DBSession()
    new_student = Student(id=10001, name="yangjian", age=18, address="chengdu")
    new_student2 = Student(id=10002, name="yangjian1", age=181, address="chengdu")
    new_student3 = Student(id=10003, name="yangjian2", age=182, address="chengdu")
    session.add(new_student)
    session.add_all([new_student1, new_student2])
    session.commit()
    session.close()

    查询

    查询是这个里面最为复杂,最为繁琐的一个步骤。
    通过Session的query()方法创建一个查询对象。这个函数的参数数量是可变的,参数可以是任何类或者是类的描述的集合。下面来看一个例子:

    my_stdent = session.query(Student).filter_by(name="yangjian").first()
    print(my_stdent)
    
    结果:
    
    <__main__.Student object at 0x032745F0>

    前面我们在赋值的时候,我们可以通过实例化一个对象,然后直接映射到数据库中,那我们在查询出来的数据sqlalchemy直接给映射成一个对象了(或者是每个元素为这种对象的列表),对象和我们创建表时候的class是一致的,我们就也可以直接通过对象的属性就可以直接调用就可以了。

    print(my_student.id, my_student.name, my_student.age, my_student.address)
    
    结果:
    (10003L, 'yangjian', 182L, 'chengdu')

    filter()  过滤表的条件

    my_stdent = session.query(Student).filter(Student.name.like("%yang%"))
    print(my_stdent)
    结果:
    SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address 
    FROM student 
    WHERE student.name LIKE %s

    根据结果,我们可以看出来,filter_by最后的结果就是一个sql语句,我们排错的时候就可以通过这个来排查我们sql是否正确。

    以下的这些过滤操作都可以在filter函数中使用:

    equals:
    query(Student).filter(Student.id == 10001)
    not equals:
    query(Student).filter(Student.id != 100)
    LIKE:
    query(Student).filter(Student.name.like(“%yang%”))

      IN:
      query(Student).filter(Student.name.in_(['yang', 'jian', 'cheng']))
      not in
      query(Student).filter(~Student.name.in_(['yang', 'jian', 'cheng']))


      AND:
      from sqlalchemy import and_
      query(Student).filter(and_(Student.name == 'yang', Student.id ==10001))
      或者
      query(Student).filter(Student.name == 'edfadfj').filter(Student.address == 'beijing')

      OR:
      from sqlalchemy import or_
      query.filter(or_(Student.name == 'fdedsfd', Student.age ==18))

    返回列表(List)和单项(Scalar)
    all() 返回一个列表

    my_stdent = session.query(Student).filter(Student.name.like("%ling%")).all()
    print(my_stdent)
    结果:
    [<__main__.Student object at 0x031405B0>, <__main__.Student object at 0x030FCA70>, <__main__.Student object at 0x031405F0>]

    可以通过遍历列表来获取每个对象。
    one() 返回且仅返回一个查询结果。当结果的数量不足一个或者多于一个时会报错。
    把上面的all改成one就报错了。
    first() 返回至多一个结果,而且以单项形式,而不是只有一个元素的tuple形式返回这个结果.

    my_stdent = session.query(Student).filter(Student.name.like("%yang%")).first()
    print(my_stdent)
    结果:
    <__main__.Student object at 0x030A3610>

    filter()和filter_by()的区别:
    Filter: 可以像写 sql 的 where 条件那样写 > < 等条件,但引用列名时,需要通过 类名.属性名 的方式。
    filter_by: 可以使用 python 的正常参数传递方法传递条件,指定列名时,不需要额外指定类名。,参数名对应名类中的属性名,但似乎不能使用 > < 等条件。

    当使用filter的时候条件之间是使用“==",fitler_by使用的是"="。

    user1 = session.query(User).filter_by(id=1).first()
    user1 = session.query(User).filter(User.id==1).first()

    filter不支持组合查询,只能连续调用filter来变相实现。
    而filter_by的参数是**kwargs,直接支持组合查询。
    比如:

    q = sess.query(IS).filter(IS.node == node and IS.password == password).all()

    更新

    更新就是查出来,直接更改就可以了

    my_stdent = session.query(Student).filter(Student.id == 10001).first()
    my_stdent.name = "hello"
    my_stdent.address = "beijing"
    session.commit()
    student1 = session.query(Student).filter(Student.id == 10001).first()
    print(student1.name, student1.address)
    结果:
    ('hello', 'beijing')

    删除

    删除其实也是跟查询相关的,直接查出来,调用delete()方法直接就可以删除掉。

    engine = create_engine('mysql+pymysql://yangjian:123456@192.168.48.131/sqlalchemy')
    DBSession = sessionmaker(bind=engine)
    session = DBSession()
    session.query(Student).filter(Student.id == 10001).delete()
    session.commit()
    session.close() 

    统计

    count()

    print(session.query(Student).filter(Student.name.like("%ng%")).count())

    分组

    group_by()

    std_group_by = session.query(Student).group_by(Student.age)
    print(std_group_by)
    结果的sql语句如下:
    SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address 
    FROM student GROUP BY student.age

    排序

    order_by()     反序在order_by里面用desc()方法

    std_ord_desc = session.query(Student).filter(Student.name.like("%yang%")).order_by(Student.id.desc()).all()
    for i in std_ord_desc:
        print(i.id)
  • 相关阅读:
    生产上第一使用线程池后的总结与反思
    20190407
    20190403
    Asp.net MVC中的ViewData与ViewBag
    easyui datagrid分页
    EF从数据库更新模型更新不到新表
    C语言 笔记(函数)
    python 写100~1000以内水仙花数
    python 求前n项阶乘的和
    python 写九九乘法表
  • 原文地址:https://www.cnblogs.com/yangjian319/p/9026494.html
Copyright © 2011-2022 走看看