在SqlAlchemy中动态创建表和ORM映射

27 投票
7 回答
44877 浏览
提问于 2025-04-15 12:08

我对关系型数据库还比较陌生,所以我更喜欢用一个好的ORM(对象关系映射)来简化操作。我花了一些时间评估不同的Python ORM,觉得SQLAlchemy是我需要的。不过,我现在遇到了一些困惑。

我需要为我应用中的每个玩家实例创建一个新的表。我想我知道怎么通过修改元数据中的表名来创建这个表,然后调用创建函数,但我对如何将它映射到一个新的动态类完全没有头绪。

有没有人能给我一些建议,帮我走出这个思维的瓶颈?这样做到底可不可以呢?

备注:如果我问的问题在其他Python ORM中更容易实现,我也很乐意尝试。请告诉我怎么做:-)

7 个回答

12

如果你想创建动态的类和表格,可以使用以下方法,这个方法是基于我在这里找到的一个教程(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)

这个技巧的好处是,现在你可以动态地向表格添加内容,而不需要事先定义列名!

这些列名可以存储在一个字符串数组中,或者你想要的任何地方,然后你就可以从那里开始。

13

这是个很老的问题。不过如果你喜欢使用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()

通过创建一个类工厂,你可以很方便地给类和数据库表起名字。

39

我们被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

就这样,你现在有了你的玩家表。

撰写回答