web-dev-qa-db-fra.com

Comment créer une seule table avec SQLAlchemy?

Je ne parviens pas à créer une seule table à l'aide de SQLAlchemy.

Je peux le créer en appelant Base.metadata.create_all(engine) mais à mesure que le nombre de tables augmente, cet appel prend beaucoup de temps.

Je crée des classes de table à la volée, puis je les remplis.

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()

J'ai vu dans le documentation que vous pouvez faire

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)

Cependant, je ne suis pas en mesure de comprendre comment faire la même chose que Table, avec declarative_base().

Comment puis-je faire cela avec des classes qui héritent de declarative_base()?

41
Lazik

Ci-dessus, l'appelable declarative_base () renvoie une nouvelle classe de base dont toutes les classes mappées devraient hériter. Une fois la définition de classe terminée, une nouvelle table et un nouveau mappeur () auront été générés.

La table et le mappeur résultants sont accessibles via __table__ et __mapper__ les attributs

(De ici )

Par conséquent:

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)

Sortie:

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

Le crédit revient à javex's commentaire/correction ou j'aurais pu suggérer quelque chose de semblable à:

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

Conseil:

L'approche utilisée dans build_daily_history_table pourrait être l'une des façons les moins élégantes de faire les choses, principalement parce qu'elle pollue/encombre le namespace .

26
Bleeding Fingers

Pour créer des tables spécifiques, il suffit de donner le paramètre tables à la méthode create_all().

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

table_objects est égal à:

table_objects = [HistoricDay.__table__]

ou

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

J'ai montré une table ici. Vous pouvez augmenter le nombre de tables comme vous le souhaitez.

Référence: http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.MetaData.create_all

3
vlyalcin

Créez toutes les tables qui n'existent pas avec une seule ligne. Il vérifiera si la table existe d'abord par défaut.

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

Créez une table cible avec table_name.

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

Cela fonctionne parfaitement avec declarative_base.

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
TABLE_PREFIX = "decision_"


class Stock(Base):
    __table= '{}stocks'.format(TABLE_PREFIX)

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

class StagePerformance(Base):
    __table= '{}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)
0
W.Perrin