sqlalchemy 同时连接多个数据库。完成flask_sqlalchemy的__bind_key__功能

转载请标明地址https://blog.csdn.net/weixin_42068117/article/details/83857355

 

https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/sql/schema.py

 

 """Symbol indicating that a :class:`.Table` or :class:`.Sequence`
    should have 'None' for its schema, even if the parent
    :class:`.MetaData` has specified a schema.
    .. versionadded:: 1.0.14
 """

def _get_table_key(name, schema):
    if schema is None:
        return name
    else:
        return schema + "." + name

       这一段代码显示的是我们给定的schema会拼接数据库的名字。大家应该可以理解是   数据库.表名  这样就不会有数据库的限制。这一段属于示例给大家理解的,如果只想知道怎么用,直接看本文最后的代码示例就可以了。

class Table(DialectKWArgs, SchemaItem, TableClause):

"""
 The :class:`.Table` object constructs a unique instance of itself based
    on its name and optional schema name within the given
    :class:`.MetaData` object. Calling the :class:`.Table`
    constructor with the same name and same :class:`.MetaData` argument
    a second time will return the *same* :class:`.Table` object - in this way
    the :class:`.Table` constructor acts as a registry function.

  :param schema: The schema name for this table, which is required if
        the table resides in a schema other than the default selected schema
        for the engine's database connection.  Defaults to ``None``.
        If the owning :class:`.MetaData` of this :class:`.Table` specifies
        its own :paramref:`.MetaData.schema` parameter, then that schema
        name will be applied to this :class:`.Table` if the schema parameter
        here is set to ``None``.  To set a blank schema name on a :class:`.Table`
        that would otherwise use the schema set on the owning :class:`.MetaData`,
        specify the special symbol :attr:`.BLANK_SCHEMA`.
        .. versionadded:: 1.0.14  Added the :attr:`.BLANK_SCHEMA` symbol to
           allow a :class:`.Table` to have a blank schema name even when the
           parent :class:`.MetaData` specifies :paramref:`.MetaData.schema`.
        The quoting rules for the schema name are the same as those for the
        ``name`` parameter, in that quoting is applied for reserved words or
        case-sensitive names; to enable unconditional quoting for the
        schema name, specify the flag
        ``quote_schema=True`` to the constructor, or use the
        :class:`.quoted_name` construct to specify the name.
"""

:param name: The name of this table as represented in the database.

参数代表数据库的名字。

def __init__(self, *args, **kw):
        """Constructor for :class:`~.schema.Table`.
        This method is a no-op.   See the top-level
        documentation for :class:`~.schema.Table`
        for constructor arguments.
        """
        # __init__ is overridden to prevent __new__ from
        # calling the superclass constructor.

在这个类的 __init__ 方法中,又对此方式介绍了一下。

 

以下是实例一,是调用的第一种方法,直接作为库名配置,这种是配置到框架内需要的。如果__table_args__有做其他配置


from flask import Flask

import datetime
from sqlalchemy import Column, String, create_engine, DateTime, func

app = Flask(__name__)

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy.orm import sessionmaker, scoped_session

# Base = declarative_base(cls=DeferredReflection)
Base = declarative_base()


class testuser(Base):
    __tablename__ = 'testuser'
    # 当前数据库名字是 test
    __table_args__ = {'schema': 'test'}

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    woncreated = Column(DateTime, default=datetime.datetime.utcnow())
    wontimestamp = Column(DateTime, default=datetime.datetime.utcnow(), onupdate=datetime.datetime.utcnow())


#
class testuser2(Base):
    __tablename__ = 'testuser2'
    
    # 关联查询的另一个数据库是 test2
    __table_args__ = {'schema': 'test2'}

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    woncreated = Column(DateTime, default=datetime.datetime.utcnow())
    wontimestamp = Column(DateTime, default=datetime.datetime.utcnow(), onupdate=datetime.datetime.utcnow())


engine = create_engine('mysql+pymysql://*****:*****@zch.zhangchenghao.cn/test')
# Base.prepare(engine)
dbsession = scoped_session(sessionmaker(
    autocommit=False, autoflush=False, bind=engine))


@app.route('/')
def index():
    import pdb;
    pdb.set_trace()
    qq = dbsession.query(testuser).join(testuser2,
                                        testuser.id == testuser2.id).all()
    return str(tuple(q.__dict__ for q in qq))


if __name__ == '__main__':
    app.run()


ORM 结果 如下,表名带前缀为数据库名
SELECT
test.testuser.id
AS
test_testuser_id, test.testuser.name
AS
test_testuser_name, test.testuser.woncreated
AS
test_testuser_woncreated, test.testuser.wontimestamp
AS
test_testuser_wontimestamp
FROM
test.testuser
INNER
JOIN
test2.testuser2
ON
test.testuser.id = test2.testuser2.id

结果

({'_sa_instance_state':, 'woncreated'
 : None, 'wontimestamp': None, 'name': '1', 'id': '1'}, {'_sa_instance_state':, 'woncreated': None, 'wontimestamp': None, 'name': '2', 'id': '2'})

以下是实例二。需要做session,map,大体还是相同的,这个用法官方文档中也有,只是比较隐蔽。




import datetime
from sqlalchemy import Column, String, DateTime

from sqlalchemy import create_engine, Index, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base, DeferredReflection
from sqlalchemy.orm import sessionmaker, scoped_session

# Base = declarative_base(cls=DeferredReflection)
Base = declarative_base()


class testuser(Base):
    __tablename__ = 'testuser'
    __table_args__ = (UniqueConstraint('id', 'name', name='user_settings_unique'),)

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    woncreated = Column(DateTime, default=datetime.datetime.utcnow())
    wontimestamp = Column(DateTime, default=datetime.datetime.utcnow(), onupdate=datetime.datetime.utcnow())
    
    '''__table_args__ = (
        UniqueConstraint('UserId', 'DeviceUUID', 'EventId', 'NotificationCategory', name='uk_NotifyPush'),
        {'schema': 'msus-service', 'extend_existing': True},
    )'''
    # 注意顺序,这是一种共同使用的方法,还有子类等方法



class testuser2(Base):
    __tablename__ = 'testuser2'
    __table_args__ = {'schema': 'test__2'}

    id = Column(String(20), primary_key=True)
    name = Column(String(20))
    woncreated = Column(DateTime, default=datetime.datetime.utcnow())
    wontimestamp = Column(DateTime, default=datetime.datetime.utcnow(), onupdate=datetime.datetime.utcnow())


engine = create_engine('mysql+pymysql://root:******@zch.zhangchenghao.cn/test')
# Base.prepare(engine)
# dbsession = scoped_session(sessionmaker(
#     autocommit=False, autoflush=False, bind=engine))
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)

session = Session()
session.connection(execution_options={
    "schema_translate_map": {"test__1": "test", "test__2": "test2"}})
import pdb;pdb.set_trace()

# will query from the ``account_one.user`` table
a = session.query(testuser2).get(1)
print(a.__dict__)

# 以下是结果和调试过程
{'_sa_instance_state': , 'wontimestamp': None, 'woncreated': None, 'id': '1', 'name': '11'}


(Pdb) print(session.query(testuser))
SELECT testuser.id AS testuser_id, testuser.name AS testuser_name, testuser.woncreated AS testuser_woncreated, testuser.wontimestamp AS testuser_wontimestamp
FROM testuser

(Pdb) print(session.query(testuser2))
SELECT test__2.testuser2.id AS test__2_testuser2_id, test__2.testuser2.name AS test__2_testuser2_name, test__2.testuser2.woncreated AS test__2_testuser2_woncreated, test__2.testuser2.wontimestamp AS test__2_testuser2_wontimestamp
FROM test__2.testuser2

(Pdb) session.get_bind()
Engine(mysql+pymysql://root:***@zch.zhangchenghao.cn/test)













这是连接相同地址的两个数据库,连接不同地址的数据库用到sqlalchemy的engine的binds, 不同的binds需要继承不同的抽象类或者有不同的设置名。

你可能感兴趣的:(new,work,study)