在SqlAlchemy中动态创建表和ORM映射
我对关系型数据库还比较陌生,所以我更喜欢用一个好的ORM(对象关系映射)来简化操作。我花了一些时间评估不同的Python ORM,觉得SQLAlchemy是我需要的。不过,我现在遇到了一些困惑。
我需要为我应用中的每个玩家实例创建一个新的表。我想我知道怎么通过修改元数据中的表名来创建这个表,然后调用创建函数,但我对如何将它映射到一个新的动态类完全没有头绪。
有没有人能给我一些建议,帮我走出这个思维的瓶颈?这样做到底可不可以呢?
备注:如果我问的问题在其他Python ORM中更容易实现,我也很乐意尝试。请告诉我怎么做:-)
7 个回答
如果你想创建动态的类和表格,可以使用以下方法,这个方法是基于我在这里找到的一个教程(http://sparrigan.github.io/sql/sqla/2016/01/03/dynamic-tables.html),我稍微修改了一下他的做法。
from sqlalchemy import create_engine
engine = create_engine('sqlite:///test.db', echo=True)
from sqlalchemy import Column, Integer,Float,DateTime, String, MetaData
metadata = MetaData()
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session() # create a Session
Base = declarative_base()
首先,你需要引入所有必要的依赖项,并创建你的会话和基础类。
动态创建的关键在于这里:
attr_dict = {'__tablename__': 'default','id': Column(Integer, primary_key=True, auto_increment=True)}
你可以仅通过这个方法创建一个表,利用 Python 中的'type'函数。
myClass = type('ClassnameHere', (Base,), attr_dict)
注意,我们传入了attr_dict,这将为我们的类提供所需的表名和列信息,但不同的是,我们是通过字符串定义类名的!这意味着你可以创建一个循环,遍历一个字符串数组,开始动态创建表格!
接下来,你只需要简单地调用
Base.metadata.create_all(engine)
因为我们创建的动态类是继承自Base,所以这个命令会自动创建表格!
你可以像这样向这个表格添加数据:
SomeRow = myClass(id='2')
session.add(SomeRow)
session.commit()
如果你不知道列名,这个方法还可以进一步扩展。只需参考文章了解如何做到这一点。
不过,你基本上会这样做:
firstColName = "Ill_decide_later"
secondColName = "Seriously_quit_bugging_me"
new_row_vals = myClass(**{firstColName: 14, secondColName: 33})
**运算符会将对象展开,这样firstColName和secondColName就会通过赋值运算符添加,这实际上和这样做是一样的:
new_row_vals = myClass(firstColName=14, secondColName=33)
这个技巧的好处是,现在你可以动态地向表格添加内容,而不需要事先定义列名!
这些列名可以存储在一个字符串数组中,或者你想要的任何地方,然后你就可以从那里开始。
这是个很老的问题。不过如果你喜欢使用ORM(对象关系映射),生成一个表对应的类其实很简单:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
Test = type('Test', (Base,), {
'__tablename__': 'test',
'test_id': Column(Integer, primary_key=True, autoincrement=True),
'fldA': Column(String),
... other columns
}
)
Base.metadata.create_all(engine)
# passed session create with sqlalchemy
session.query(Test).all()
通过创建一个类工厂,你可以很方便地给类和数据库表起名字。
我们被SQLAlchemy宠坏了。
下面的内容直接来自于教程,
设置和使用起来非常简单。
因为这个过程非常常见,
所以文档在2011年8月就转向了完整的声明式。
设置你的环境(我在用SQLite的内存数据库来测试):
>>> from sqlalchemy import create_engine
>>> engine = create_engine('sqlite:///:memory:', echo=True)
>>> from sqlalchemy import Table, Column, Integer, String, MetaData
>>> metadata = MetaData()
定义你的表:
>>> players_table = Table('players', metadata,
... Column('id', Integer, primary_key=True),
... Column('name', String),
... Column('score', Integer)
... )
>>> metadata.create_all(engine) # create the table
如果你开启了日志记录,你会看到SQLAlchemy为你生成的SQL语句。
定义你的类:
>>> class Player(object):
... def __init__(self, name, score):
... self.name = name
... self.score = score
...
... def __repr__(self):
... return "<Player('%s','%s')>" % (self.name, self.score)
将类映射到你的表:
>>> from sqlalchemy.orm import mapper
>>> mapper(Player, players_table)
<Mapper at 0x...; Player>
创建一个玩家:
>>> a_player = Player('monty', 0)
>>> a_player.name
'monty'
>>> a_player.score
0
就这样,你现在有了你的玩家表。