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

27 人关注

我对使用关系型数据库相当陌生,所以我更喜欢使用一个好的ORM来简化事情。 我花时间评估了不同的Python ORM,我认为SQLAlchemy是我需要的。 然而,我已经走到了一个心理死胡同。

我需要创建一个新的表来配合我在应用程序的播放器表中创建的每个播放器实例。我想我知道如何通过元数据改变表的名称,然后调用创建函数来创建表,但我不知道如何把它映射到一个新的动态类。

谁能给我一些提示,帮助我克服大脑冻结的问题?这有可能吗?

注意:如果我要求的东西更容易实现,我对Python中的其他ORM持开放态度。只要告诉我怎么做就可以了:-)

4 个评论
创建动态表是一个坏主意。 在表中添加一个键来区分球员的实例是一个好主意。 你想通过这个 "动态表 "业务实现什么?
基本上,每个球员都有自己的分数表,以跟踪他们的分数随着时间的推移。 玩家可以在任何时间点加入,所以很难在一个巨大的分数表中追踪所有玩家的分数......至少对我来说是这样。
当然,提出这个问题的过程让我从一个全新的角度去思考这个问题。 我也许可以创建一个巨大的分数表,在一列中包括球员的ID和他们的分数信息。然后我可以对球员的ID做一个查询,以拉出他们的分数。 谢谢大家。
是的,这(得分表中的球员ID的外键)正是正确的方法。你说,"我对使用关系型数据库相当陌生,所以我更喜欢使用一个好的ORM来简化事情,"但是你真的应该花时间来学习关系型数据库的工作原理,即使你使用的是ORM,否则你会得到糟糕的模式和查询结果。
python
database
sqlalchemy
Jay Atkinson
Jay Atkinson
发布于 2009-06-10
7 个回答
mechanical_meat
mechanical_meat
发布于 2013-05-09
已采纳
0 人赞同

我们被SQLAlchemy宠坏了。
以下内容直接取自 教程 ,
而且真的很容易设置和工作。

而且因为它是如此频繁地进行。
文件 转为完全声明式 在2011年8月。

Setup your environment (I'm using the SQLite in-memory db to test):

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

就这样,你现在有了一个你的球员表。

谢谢你的信息。 这并不是我所寻找的。 我正在尝试超越这一点,每个玩家有另一张桌子。
我不明白最后一块代码显示了什么。在没有任何sqlalchemy映射的情况下,我可以得到这样的输出,对吗?
igolkotek
igolkotek
发布于 2013-05-09
0 人赞同

这是个很老的问题。总之,如果你喜欢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()

制作一个类工厂,很容易给类和数据库表分配名称。

Joseph Astrahan
Joseph Astrahan
发布于 2013-05-09
0 人赞同

如果你想创建动态类和表,你可以使用以下技术,这些技术基于我在这里找到的这个教程网址( 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)}

你可以通过利用以下方法来创建一个表格'type' function in python.

myClass = type('ClassnameHere', (Base,), attr_dict)

注意,我们传递的是attr_dict, this will give the required 标签名和专栏信息给我们的班级,但不同的是我们是通过一个字符串定义类的名称!这意味着你可以创建一个循环,例如通过一个字符串数组,开始动态地创建表格

接下来你所要做的就是简单地调用

Base.metadata.create_all(engine)

因为我们创建的动态类继承于基地该命令将简单地创建这些表格。

你现在这样添加到这个表中,比如说。

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)

这种技术的优点是现在你可以动态地添加到表中,甚至不需要定义列名!

例如,这些列名可以存储在一个字符串数组中,或任何你想要的东西,你只需从那里取。

Anurag Uniyal
Anurag Uniyal
发布于 2013-05-09
0 人赞同

也许看一下 SQLSoup ,这是在SQLAlchemy之上的一层。

你也可以用普通的SQL来创建表,并且要动态映射,如果这些库已经没有创建表的功能,就使用这些库。

或者也可以创建一个动态类并对其进行映射。

tableClass = type(str(table.fullname), (BaseTable.BaseTable,), {})
mapper(tableClass, table)

其中 BaseTable 可以是任何你希望所有的表类都继承自的 Python 类,例如,这样的 Base 类可能有一些实用或通用的方法,例如基本的 CRUD 方法。

class BaseTable(object): pass

否则,你不需要向type(...)传递任何基础。

我从哪里导入BaseTable?我在sqlalchemy中找不到它。
Mike
Elixir自2009年以来一直没有更新,似乎已经被放弃了。 它不支持python 2.7以上版本。
Nazmul Hasan
Nazmul Hasan
发布于 2013-05-09
0 人赞同

你可以使用声明式方法在数据库中动态地创建表

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
Base = declarative_base()
class Language(Base):
    __tablename__ = 'languages'
    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    extension = Column(String(20))
    def __init__(self, name, extension):
        self.name = name
        self.extension = extension
    
user195454
user195454
发布于 2013-05-09
0 人赞同

当我试图使用SQLAlchemy自动化简单的CRUD任务时,我也面临同样的问题。 下面是简单的解释和一些代码。 http://www.devx.com/dbzone/Article/42015

madjardi
madjardi
发布于 2013-05-09
0 人赞同

也许我不太明白你想要什么,但这个配方在不同的__tablename__中创建了相同的列。

class TBase(object):
    """Base class is a 'mixin'.
    Guidelines for declarative mixins is at:
    http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#mixin-classes
    id = Column(Integer, primary_key=True)
    data = Column(String(50))
    def __repr__(self):
        return "%s(data=%r)" % (
            self.__class__.__name__, self.data
class T1Foo(TBase, Base):
    __tablename__ = 't1'
class T2Foo(TBase, Base):
    __tablename__ = 't2'
engine = create_engine('sqlite:///foo.db', echo=True)
Base.metadata.create_all(engine)
sess = sessionmaker(engine)()
sess.add_all([T1Foo(data='t1'), T1Foo(data='t2'), T2Foo(data='t3'),
         T1Foo(data='t4')])
print sess.query(T1Foo).all()