简体   繁体   English

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

[英]Dynamic Table Creation and ORM mapping in SqlAlchemy

I'm fairly new to using relational databases, so I prefer using a good ORM to simplify things.我对使用关系数据库还很陌生,所以我更喜欢使用好的 ORM 来简化事情。 I spent time evaluating different Python ORMs and I think SQLAlchemy is what I need.我花时间评估了不同的 Python ORM,我认为 SQLAlchemy 正是我所需要的。 However, I've come to a mental dead end.然而,我已经到了精神上的死胡同。

I need to create a new table to go along with each instance of a player I create in my app's player table.我需要创建一个新表,以配合我在应用程序的播放器表中创建的每个播放器实例。 I think I know how to create the table by changing the name of the table through the metadata then calling the create function, but I have no clue on how to map it to a new dynamic class.我想我知道如何通过元数据更改表的名称然后调用 create 函数来创建表,但我不知道如何将其映射到新的动态类。

Can someone give me some tips to help me get past my brain freeze?有人可以给我一些提示来帮助我摆脱大脑冻结吗? Is this even possible?这甚至可能吗?

Note: I'm open to other ORMs in Python if what I'm asking is easier to implement.Just show me how :-)注意:如果我要问的更容易实现,我对 Python 中的其他 ORM 持开放态度。只要告诉我如何:-)

We are spoiled by SQLAlchemy.我们被 SQLAlchemy 宠坏了。
What follows below is taken directly from the tutorial ,以下内容直接取自教程
and is really easy to setup and get working.并且非常容易设置和开始工作。

And because it is done so often,而且因为经常这样做,
the documentation moved to full declarative in Aug 2011.该文档于 2011 年 8 月变为完全声明性的

Setup your environment (I'm using the SQLite in-memory db to test):设置您的环境(我正在使用 SQLite 内存数据库进行测试):

>>> from sqlalchemy import create_engine
>>> engine = create_engine('sqlite:///:memory:', echo=True)
>>> from sqlalchemy import Table, Column, Integer, String, MetaData
>>> metadata = MetaData()

Define your table:定义你的表:

>>> players_table = Table('players', metadata,
...   Column('id', Integer, primary_key=True),
...   Column('name', String),
...   Column('score', Integer)
... )
>>> metadata.create_all(engine) # create the table

If you have logging turned on, you'll see the SQL that SQLAlchemy creates for you.如果您打开了日志记录,您将看到 SQLAlchemy 为您创建的 SQL。

Define your class:定义你的类:

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

Map the class to your table:将类映射到您的表:

>>> from sqlalchemy.orm import mapper
>>> mapper(Player, players_table) 
<Mapper at 0x...; Player>

Create a player:创建一个播放器:

>>> a_player = Player('monty', 0)
>>> a_player.name
'monty'
>>> a_player.score
0

That's it, you now have a your player table.就是这样,你现在有一个你的玩家表。

It's a very old question.这是一个非常古老的问题。 Anyway if you prefer ORM, it's quite easy to generate table class with type:无论如何,如果您更喜欢 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()

Making a class factory, it's easy to assign names to a class and database table.制作类工厂,很容易为类和数据库表分配名称。

If you are looking to create dynamic classes and tables you can use the following technique based from this tutorial URL I found here ( http://sparrigan.github.io/sql/sqla/2016/01/03/dynamic-tables.html ), I modified how he did it a bit.如果您正在寻找创建动态类和表,您可以使用以下基于我在此处找到的教程 URL 的技术( 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()

First include all the needed dependencies and create your session and Base.首先包含所有需要的依赖项并创建您的会话和 Base。

The key to creating it dynamically is this here:动态创建它的关键在这里:

attr_dict = {'__tablename__': 'default','id': Column(Integer, primary_key=True, auto_increment=True)}

you could create a table from just this by taking advantage of the 'type' function in python.您可以通过利用 python 中的“类型”函数来创建一个表。

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

Note that we are passing in attr_dict , this will give the required tablename and column information to our class, but the difference is we are defining the class name through a string!请注意,我们传入的是attr_dict ,这将为我们的类提供所需的表名和列信息,但不同之处在于我们通过字符串定义类名! This means you could create a loop for example going through an array of strings to start creating tables dynamically!这意味着您可以创建一个循环,例如遍历字符串数组以开始动态创建表!

Next all you have to do is simply call接下来你要做的就是简单地调用

Base.metadata.create_all(engine)

Because the dynamic class we created inherits from Base the command will simply create the tables!因为我们创建的动态类继承自Base该命令将简单地创建表!

You add to this table for example like this now:您现在添加到此表中,例如:

SomeRow = myClass(id='2')
session.add(SomeRow)
session.commit()

This can go even further if you you don't know the column names as well.如果您也不知道列名,这可以更进一步。 Just refer to the article to learn how to do that.只需参考文章即可了解如何执行此操作。

You would essentially do something like this though:你基本上会做这样的事情:

firstColName = "Ill_decide_later"
secondColName = "Seriously_quit_bugging_me"

new_row_vals = myClass(**{firstColName: 14, secondColName: 33})

The ** operator takes the object and unpacks it so that firstColName and secondColName are added with assignment operators so it would essentially be the same thing as this: ** 运算符获取对象并将其解包,以便 firstColName 和 secondColName 添加赋值运算符,因此它本质上与此相同:

new_row_vals = myClass(firstColName=14, secondColName=33)

The advantage of this technique is now you can dynamically add to the table without even having to define the column names!这种技术的优点是现在您可以动态添加到表中,甚至不必定义列名!

These column names could be stored in a string array for example or whatever you wanted and you just take it from there.例如,这些列名可以存储在字符串数组中,或者您想要的任何内容中,您只需从那里获取它。

Maybe look at SQLSoup , which is layer over SQLAlchemy.也许看看SQLSoup ,它是 SQLAlchemy 上的一层。

You can also create the tables using plain SQL, and to dynamically map, use these libraries if they already don't have create table function.您还可以使用普通 SQL 创建表,并动态映射,如果这些库没有创建表功能,请使用这些库。

Or alternatively create a dynamic class and map it:或者创建一个动态类并映射它:

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

where BaseTable can be any Python class which you want all your table classes to inherit from, eg such Base class may have some utility or common methods, eg basic CRUD methods:其中 BaseTable 可以是您希望所有表类都继承自的任何 Python 类,例如此类Base类可能具有一些实用程序或通用方法,例如基本的 CRUD 方法:

class BaseTable(object): pass

Otherwise you need not pass any bases to type(...) .否则,您无需将任何基数传递给type(...)

you can use declarative method for dynamically creating tables in database您可以使用声明性方法在数据库中动态创建表

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

I faced the same problem when I was trying to automate simple CRUD tasks using SQLAlchemy.当我尝试使用 SQLAlchemy 自动执行简单的 CRUD 任务时,我遇到了同样的问题。 Here is simple explanation and some code: http://www.devx.com/dbzone/Article/42015这是简单的解释和一些代码: http : //www.devx.com/dbzone/Article/42015

maybe i didn't quite understand what you want, but this recipe create identical column in different __tablename__也许我不太明白你想要什么,但是这个食谱在不同的 __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()
print sess.query(T2Foo).all()
sess.commit()

info in example sqlalchemy 示例 sqlalchemy 中的信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM