如何使用 SQLAlchemy 只创建一张表?

Posted

技术标签:

【中文标题】如何使用 SQLAlchemy 只创建一张表?【英文标题】:How to create only one table with SQLAlchemy? 【发布时间】:2013-10-11 02:28:14 【问题描述】:

我无法使用 SQLAlchemy 创建单个表。

我可以通过调用Base.metadata.create_all(engine)来创建它,但是随着表的数量增加,这个调用需要很长时间。

我动态创建表类,然后填充它们。

from sqlalchemy import create_engine, Column, Integer, Sequence, String, Date, Float, BIGINT
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class HistoricDay():

    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    #  Date, Open, High, Low, Close, Volume, Adj Close
    date = Column(Date)
    open = Column(Float)
    high = Column(Float)
    low = Column(Float)
    close = Column(Float)
    volume = Column(BIGINT)
    adjClose = Column(Float)

    def __init__(self, date, open, high, low, close, volume, adjClose):
        self.date = date
        self.open = open
        self.high = high
        self.low = low
        self.close = close
        self.volume = volume
        self.adjClose = adjClose

def build_daily_history_table_repr(self):
        return "<"+self.__tablename__+"('','','','','','','','')>".format(self.id, self.date, self.open, self.high, self.low, self.close, self.volume, self.adjClose)

def build_daily_history_table(ticket):
    classname = ticket+"_HistoricDay"
    globals()[classname] = type(classname, (HistoricDay,Base), '__tablename__' : ticket+"_daily_history")
    setattr(globals()[classname], '__repr__', build_daily_history_table_repr)

# Initialize the database :: Connection & Metadata retrieval
engine = create_engine('mysql+cymysql://root@localhost/gwc?charset=utf8&use_unicode=0', pool_recycle=3600) # ,echo = True

# SqlAlchemy :: Session setup
Session = sessionmaker(bind=engine)

# Create all tables that do not already exist
Base.metadata.create_all(engine)

# SqlAlchemy :: Starts a session
session = Session()

ticketList = getTicketList()

for ticket in ticketList:
    build_daily_history_table(ticket)
    class_name = ticket+"_HistoricDay"

    meta_create_all_timer = time.time()
    # Create all tables that do not already exist
    # globals()[class_name]('2005-07-24',0,0,0,0,0,0).create(engine)  #doesn't work
    #(globals()[class_name]).__table__.create(engine) #doesn't work
    # session.commit() #doesn't work

    #Base.metadata.create_all(engine) # works but gets very slow
    print("  meta_create_all_timer s".format(time.time()-meta_create_all_timer))

    data = getData(ticket)

    for m_date, m_open, m_close, m_high, m_low, m_volume, m_adjClose in data:
        entry = globals()[class_name](m_date, m_open, m_high, m_low, m_close, m_volume, m_adjClose)
        session.add(entry)

    session.commit()

我在documentation看到你可以做

engine = create_engine('sqlite:///:memory:')

meta = MetaData()

employees = Table('employees', meta,
    Column('employee_id', Integer, primary_key=True),
    Column('employee_name', String(60), nullable=False, key='name'),
    Column('employee_dept', Integer, ForeignKey("departments.department_id"))
)
employees.create(engine)

但是,我无法弄清楚如何使用declarative_base() 做与Table 相同的事情。

如何使用继承自 declarative_base() 的类来做到这一点?

【问题讨论】:

应该是HistoricDay(Base) 否,因为 HistoricDay 没有属性表名。生成的类继承自 Base : globals()[classname] = type(classname, (HistoricDay,Base), 'tablename' : ticket+"_daily_history") 【参考方案1】:

上面,declarative_base() 可调用返回一个新的基类 所有映射的类都应该继承。当类定义是 完成后,就会生成一个新的 Table 和 mapper()。

结果表和映射器可通过__table____mapper__属性

(来自here)

因此:

def build_daily_history_table(ticket):
    classname = ticket + "_HistoricDay"
    ticket = type(classname, (Base, HistoricDay), '__tablename__' : ticket+"_daily_history")
    ticket.__repr__ =  build_daily_history_table_repr
    return ticket

build_daily_history_table("test").__table__.create(bind = engine)

输出:

2013-10-04 22:36:53,263 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE test_daily_history (
    id INTEGER NOT NULL, 
    date DATE, 
    open FLOAT, 
    high FLOAT, 
    low FLOAT, 
    close FLOAT, 
    volume BIGINT, 
    "adjClose" FLOAT, 
    PRIMARY KEY (id)
)


2013-10-04 22:36:53,263 INFO sqlalchemy.engine.base.Engine ()
2013-10-04 22:36:53,263 INFO sqlalchemy.engine.base.Engine COMMIT

感谢 javex's 评论/更正,或者我可能提出了类似的建议:

Base.metadata.tables["ticket_daily_history"].create(bind = engine)

建议:

build_daily_history_table 中使用的方法可能是最不优雅的做事方式之一,主要是因为它污染/弄乱了namespace。

【讨论】:

我试过了,但是Traceback (most recent call last): File "autoPopulate.py", line 493, in &lt;module&gt; m_init() File "autoPopulate.py", line 422, in m_init state = success_state(ticket) File "autoPopulate.py", line 306, in success_state globals()[class_name].create(engine) AttributeError: type object 'HMN_HistoricDay' has no attribute 'create' HistoricDay.__table__.create(engine) 使用 cymysql 连接器,我不得不使用__table__.create(engine, checkfirst=True) 据我所知,@javex 的评论是我们大多数人在这里寻找的内容,因此在问题中多强调一下可能会有用。【参考方案2】:

要创建特定的表,将tables 参数传递给create_all() 方法就足够了。

Base.metadata.create_all(engine, tables=table_objects)

table_objects 等于:

table_objects = [HistoricDay.__table__]

table_objects = [Base.metadata.tables["historicday"]]

我在这里展示了一张桌子。您可以根据需要增加表的数量。

参考: http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.MetaData.create_all

【讨论】:

第二个选项对我有用:Base.metadata.create_all(engine, tables=[Product.__table__])。谢谢【参考方案3】:

用一行创建所有不存在的表。默认先检查表是否存在。

Base.metadata.create_all(db_engine, Base.metadata.tables.values(),checkfirst=True)

使用table_name 创建一个目标表。

Base.metadata.create_all(db_engine, Base.metadata.tables[table_name],checkfirst=True)

它与declarative_base完美配合。

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
TABLE_PREFIX = "decision_"


class Stock(Base):
    __tablename__ = 'stocks'.format(TABLE_PREFIX)

    id = Column(Integer, primary_key=True)
    name = Column(String)

class StagePerformance(Base):
    __tablename__ = 'stage_performance'.format(TABLE_PREFIX)

    id = Column(Integer, primary_key=True)
    date = Column(DateTime)
    stock = relationship("Stock", back_populates="stage_performances")
    period = Column(Integer )
    open = Column(Float)
    high = Column(Float)
    low = Column(Float)
    close = Column(Float)
    change_ratio = Column(Float)
    turnover = Column(Float)
    volume = Column(Float)

【讨论】:

以上是关于如何使用 SQLAlchemy 只创建一张表?的主要内容,如果未能解决你的问题,请参考以下文章

如何确保 MainActivity 只创建一次

如何让 OpenMP 在程序每次运行时只创建一次线程?

在 Cloud Firestore 中如何制作一个,只创建一次安全规则

如何在 C++ 中并行化一个 for 循环,只创建一次线程池

如何在一个包含多个 matplotlib 直方图的图中设置 x 轴的边界并只创建一列图?

Sprite Kit:为所有场景只创建一次节点