0

在将 sqlalchemy 映射设置到 python 中的 sqlite 数据库时,我有一个关于“安排代码,这取决于彼此”的小问题。

目标是编写一个脚本,它满足以下条件:

  1. 获取一个filename参数作为命令行参数。
  2. 基于filename它应该创建一个 SQLite 数据库的绝对路径。
  3. 它应该连接到数据库并创建一个engine
  4. 它应反映该数据库中的表。
  5. 它应该将表中monkey patch的列作为主键列,因为该表没有主键并且 sqlalchemy 需要一个。idmytable

所以我想出了这个:

from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base  

def create_path(file_name):
    # generate absolute path to file_name

path_to_file = create_path("my_file_name.sqlite")
engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False)
Base = declarative_base()
Base.metadata.create_all(engine)

class MyTable(Base):
    __tablename__ = 'my_table'
    __table_args__ = {'autoload': True}

    id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key.

def main(argv):
    # parse file_name here from argv
    Session = sessionmaker(bind=engine)
    session = Session()
    for row in session.query(MyTable).all():
        print row
    return "Stop!"

if __name__ == '__main__':
    sys.exit(main())

But this is a doomed construction and I don't see how I could rearrange my code without breaking the dependencies.

  1. To be able to create MyClass I need Base to be defined before MyClass.
  2. To be able to create Base I need engine to be defined before Base.
  3. To be able to create engine I need path_to_file to be defined before engine.
  4. To be able to create path_to_file outside of main() I need create_file() to be defined before path_to_file.
  5. And so on...

Hopefully you see where I am stuck...

Any suggestions?

Edit: By the way, the code works, but only with a hardcoded filename in the top of the script.

4

3 回答 3

1

I solved my problem using the classical mapping approach of SQLAlchemy:

from sqlalchemy import create_engine, Column, Integer, MetaData, Table
from sqlalchemy.orm import sessionmaker, mapper

class MyTable(object):    
    pass    

def main():
    path_to_file = create_path("my_file_name.sqlite")
    engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False)

    metadata = MetaData()
    metadata.bind = engine
    my_table = Table('mytable',
                     metadata,
                     Column('id', Integer, primary_key=True), # Monkey patching the id column as primary key.
                     autoload=True,
                     autoload_with=engine)
    mapper(MyTable, my_table)

    Session = sessionmaker(bind=engine)
    session = Session()

    # Do Stuff!
于 2012-04-07T08:08:25.203 回答
1

I do not see why you could not use the declarative mapping still complety. I think the key to the proper dependencies is to know what to put in the module and what in the script/function. With python, you can easily define the class inside the run_script function.

from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

def create_path(filename):
    import os
    fn = os.path.abspath(os.path.join(os.path.dirname(__file__), 'sqlite_files', filename))
    return fn

def run_script(filename):
    path_to_file = create_path(filename)

    engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=True)
    Session = sessionmaker(bind=engine)
    Base = declarative_base(bind=engine)

    # object model
    class MyTable(Base):
        __tablename__ = 'my_table'
        __table_args__ = {'autoload': True}
        id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key

    # script itself
    session = Session()
    for row in session.query(MyTable).all():
        print row
    return "Stop!"

def main(argv):
    assert argv, "must specify a database file name"
    run_script(argv[0])

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))
于 2012-04-12T16:00:27.653 回答
0

I don't have the capability to do any testing at my current location. But I suggest moving all of that code to main() as follows. Also, MyTable subclasses declarative_base.

from sqlalchemy import create_engine, Column, Integer 
from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base    

class MyTable(declarative_base):     
    __tablename__ = 'my_table'     
    __table_args__ = {'autoload': True}      

    id = Column(Integer, primary_key=True) # Monkey patching the id column as primary key.  

def create_path(file_name):     
    # generate absolute path to file_name  


def main(argv):     # parse file_name here from argv   
    path_to_file = create_path("my_file_name.sqlite") 
    engine = create_engine('sqlite:///{path}'.format(path=path_to_file), echo=False) 
    Base = MyTable()
    Base.metadata.create_all(engine)  

    Session = sessionmaker(bind=engine)     
    session = Session()     
    for row in session.query(MyTable).all():         
        print row     
    return "Stop!"  

if __name__ == '__main__':     
    sys.exit(main()) 
于 2012-04-05T20:53:24.163 回答