oslo sqlalchemy 使用范例

oslo db 是oslo系列工具库里专用于管理数据库连接、管理的工具。它主要对sqlalchemy做进一步封装使用。
github官网: https://github.com/openstack/oslo.db

使用:

一、定义models:

from sqlalchemy import Column, Integer, String, Float, SmallInteger, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, column_property, relationship, validates

BASE = declarative_base()


class Country(BASE):
    __tablename__ = "country"
    Code = Column(String(3), nullable=False, primary_key=True)
    Name = Column(String(52), nullable=False)
    Continent = Column(String(25), nullable=False)
    Region = Column(String(26), nullable=False)
    SurfaceArea = Column(Float(10, 2), nullable=False)
    IndepYear = Column(SmallInteger, nullable=False)
    Population = Column(Integer, nullable=False)
    LifeExpectancy = Column(Float(3, 1))
    GNP = Column(Float(10, 2))
    GNPOld = Column(Float(10, 2))
    LocalName = Column(String(45), nullable=False)
    GovernmentForm = Column(String(45), nullable=False)
    HeadOfState = Column(String(60))
    Capital = Column(Integer)
    Code2 = Column(String(2), nullable=False)


class City(BASE):
    __tablename__ = "city"
    ID = Column(Integer, primary_key=True)
    Name = Column(String(35), nullable=False)
    CountryCode = Column(String(3), ForeignKey('country.Code'), nullable=False)
    District = Column(String(20), nullable=False)
    Population = Column(Integer, nullable=False)

一、常用操作

# -*- coding:utf-8 -*-

from oslo_db import exception as db_exc
from oslo_db import options
from oslo_db.sqlalchemy import session as db_session

import sqlalchemy
from sqlalchemy import MetaData
from sqlalchemy import or_, and_, case
from sqlalchemy.orm import joinedload, joinedload_all, undefer_group
from sqlalchemy.orm import RelationshipProperty
from sqlalchemy import sql
from sqlalchemy.sql.expression import bindparam
from sqlalchemy.sql.expression import desc
from sqlalchemy.sql.expression import literal_column
from sqlalchemy.sql.expression import true
from sqlalchemy.sql import func
from sqlalchemy.sql import sqltypes
from sqlalchemy import text

from models import City, Country

_FACADE = None


def _create_facade_lazily():
    """
    加载
    :return: 
    """
    global _FACADE
    if _FACADE is None:
        _FACADE = db_session.EngineFacade(
            'mysql+pymysql://root:wyue@localhost:3306/world?charset=latin1'
        )

    return _FACADE


def get_engine():
    """
    获得引擎
    :return: 
    """
    facade = _create_facade_lazily()
    return facade.get_engine()


def get_session(**kwargs):
    """
    获得会话
    :param kwargs: 
    :return: 
    """
    facade = _create_facade_lazily()
    return facade.get_session(**kwargs)


def dispose_engine():
    get_engine().dispose()


def print_city_info(city=None, country=None):
    """
    打印信息
    :param city: 
    :param country: 
    :return: 
    """
    info = {}
    if city:
        city_info = {'id': city.ID, 'name': city.Name, 'country_code': city.CountryCode, 'district': city.District,
                     'population': city.Population}
        info.update({'city': city_info})
    if country:
        country_info = {'code': country.Code, 'name': country.Name, 'continent': country.Continent,
                        'region': country.Region,
                        'surfaceArea': country.SurfaceArea, 'IndepYear': country.IndepYear}
        info.update({'country': country_info})
    print info


def query_city_all():
    """
    查询所有
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City)
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_filter1():
    """
    单条件查询
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(City.Name == 'Gaza')
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_filter2():
    """
    多条件查询
    :return:
    """
    session = get_session()
    with session.begin():
        condition = {'CountryCode': 'GBR', 'District': 'England'}
        query = session.query(City).filter_by(**condition)
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_AND():
    """
    使用AND运算符
    :return:
    """
    session = get_session()
    with session.begin():
        condition = [City.CountryCode == 'GBR', City.District == 'England', City.Name == 'Birkenhead']
        query = session.query(City).filter(and_(*condition))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_OR():
    """
    使用OR运算符
    :return:
    """
    session = get_session()
    with session.begin():
        condition = [City.District == 'England', City.Name == 'Birkenhead']
        query = session.query(City).filter(or_(*condition))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_AND_OR():
    """
    使用OR + AND 运算符
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(and_(
            City.CountryCode == 'GBR',
            or_(
                City.Name == 'Maidstone',
                City.Population == 91069
            )
        ))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_IN():
    """
    使用 IN 运算符
    :return:
    """
    session = get_session()
    with session.begin():
        ids = [1, 2, 3, 5, 6, 8]
        query = session.query(City).filter(City.ID.in_(ids))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_LIKE():
    """
    使用 like 运算符模糊查询
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(City.Name.like('He%'))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_union():
    """
    使用 union 集合查询
    :return:
    """
    session = get_session()
    with session.begin():
        query1 = session.query(City).filter(City.Name.like('He%'))
        ids = [1, 2, 3, 5, 6, 8]
        query2 = session.query(City).filter(City.ID.in_(ids))
        query = query1.union(query2)
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_with_exists():
    """
    使用 exist 集合查询

    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(sql.exists().where(and_(
            City.CountryCode == Country.Code,
            Country.Name == 'Aruba'
        )))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def query_city_country_join():
    """
    连接查询
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City.Name, Country.Name).join(Country).filter(Country.Name == 'Aruba')
        print 'SQL : %s' % str(query)
        print query.first()
        # for c in query.all():
        #     print_city_info(c)


def query_city_group_by():
    """
    group by 、sum求和、count求总数
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City.CountryCode, func.count(City.ID), func.sum(City.Population)). \
            group_by(City.CountryCode). \
            having(and_(
            func.count(City.ID) > 10,
            func.sum(City.Population) > 85699060))
        print 'SQL : %s' % str(query)
        print query.all()


def query_city_sub_query():
    """
    子查询

    SQL : SELECT country."Code" AS "country_Code", country."Name" AS "country_Name", country."Continent" AS "country_Continent", country."Region" AS "country_Region", country."SurfaceArea" AS "country_SurfaceArea", country."IndepYear" AS "country_IndepYear", country."Population" AS "country_Population", country."LifeExpectancy" AS "country_LifeExpectancy", country."GNP" AS "country_GNP", country."GNPOld" AS "country_GNPOld", country."LocalName" AS "country_LocalName", country."GovernmentForm" AS "country_GovernmentForm", country."HeadOfState" AS "country_HeadOfState", country."Capital" AS "country_Capital", country."Code2" AS "country_Code2"
FROM country
WHERE country."Code" IN (SELECT city."CountryCode"
FROM city GROUP BY city."CountryCode"
HAVING count(city."ID") > :count_1 AND sum(city."Population") > :sum_1)
    :return:
    """
    session = get_session()
    with session.begin():
        stmt = session.query(City.CountryCode). \
            group_by(City.CountryCode). \
            having(and_(
            func.count(City.ID) > 10,
            func.sum(City.Population) > 85699060)).subquery()
        query = session.query(Country).filter(Country.Code.in_(stmt))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(country=c)


def query_city_with_sql():
    """
    执行sql
    :return:
    """
    session = get_session()
    with session.begin():
        qrySql = "select CountryCode as country_code, count(ID) cnt from city group by CountryCode having count(ID) > 20"
        query = session.query('country_code', 'cnt').from_statement(text(qrySql))
        print 'SQL : %s' % str(query)
        rows = query.all()
        for row in rows:
            print 'country_code : %s , cnt : %s ' % row


def query_city_order_limit():
    """
    排序、分页
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).order_by(City.ID).limit(10).offset(5)
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


def update_city():
    """
    修改信息
    :return:
    """
    session = get_session()
    with session.begin():
        print 'before update:'
        query = session.query(City).filter(City.ID == 1)
        print 'SQL : %s' % str(query)
        print_city_info(query.first())

        print '1  after update:'
        query.update({City.Population: 4022222})
        # 使用update方法
        print_city_info(query.first())

        print '2  after update:'
        # 使用赋值法
        c = query.first()
        c.Population = 10
        print_city_info(query.first())


def add_city():
    """
    修改信息
    :return:
    """
    session = get_session()
    with session.begin():
        c = City()
        c.Name = 'SanMing2'
        c.CountryCode = 'CHN'
        c.District = 'Fujian'
        c.Population = 160691
        session.add(c)

        query = session.query(City).filter(City.Name.like('SanMing%'))
        for c in query.all():
            print_city_info(c)


def delete_city():
    """
    删除数据
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(City.Name == 'SanMing2').delete()

        query = session.query(City).filter(City.Name.like('SanMing%'))
        for c in query.all():
            print_city_info(c)


def delete_city_in():
    """
    用 in 作条件 删除数据
    :return:
    """

    session = get_session()
    with session.begin():
        print 'before delete'
        query1 = session.query(City.ID).filter(City.Name.like('SanMin%'))
        print query1.all()
        # 删除记录时,默认会尝试删除 session 中符合条件的对象,而 in 操作估计还不支持,于是就出错了。
        # 解决办法就是删除时不进行同步,然后再让 session 里的所有实体都过期
        # 此外,update 操作也有同样的参数,如果后面立刻提交了,那么加上 synchronize_session=False 参数会更快。
        session.query(City).filter(City.ID.in_(range(4086, 4096))).delete(synchronize_session=False)

def query_city_with_IN():
    """
    使用 between 运算符, between 8 and 10
    SQL : SELECT city."ID" AS "city_ID", city."Name" AS "city_Name", city."CountryCode" AS "city_CountryCode", city."District" AS "city_District", city."Population" AS "city_Population" 
FROM city 
WHERE city."ID" BETWEEN :ID_1 AND :ID_2
    :return:
    """
    session = get_session()
    with session.begin():
        query = session.query(City).filter(City.ID.between(8,10))
        print 'SQL : %s' % str(query)
        for c in query.all():
            print_city_info(c)


if __name__ == '__main__':
    delete_city_in()



二、遇到的错误:

错误日志:

oslo_db.exception.DBError: (pymysql.err.InternalError) (1093, u"You can't specify target table 'city' for update in FROM clause")
[SQL: u'DELETE FROM city WHERE city.`ID` IN (SELECT city.`ID` \nFROM city \nWHERE city.`Name` = %(Name_1)s)'] [parameters: {u'Name_1': 'SanMing2'}]

出错的代码:

    session = get_session()
    with session.begin():
        stmt = session.query(City.ID).filter(City.Name == 'SanMing2').subquery()
        session.query(City).filter(City.ID.in_(stmt)).delete(synchronize_session=False)

原因:

mysql中You can't specify target table for update in FROM clause错误的意思是说,不能先select出同一表中的某些值,再在同一语句中修改或删除这些值!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容