peewee:重用动态创建的模型

hit*_*tzg 3 python-2.7 peewee

在我的应用程序中,我有一个模型,我只在运行时知道它的列数。使用Factory如下函数创建模型可以很好地解决这个问题。但是,如果我多次使用它(可能有不同的字段),外键的创建ref会引发异常:

AttributeError: Foreign key: dynamictable.ref related name "dynamictable_set" 
collision with foreign key using same related_name.
Run Code Online (Sandbox Code Playgroud)

该消息非常清楚,当我related_name在创建外键时设置参数时没有错误。

问题

  1. 为什么我不能related_name第二次使用相同的?我也需要重新定义StaticTable吗?

  2. 有没有更好的方法来使用动态模型写入多个数据库?

最小的、可重现的例子:

import peewee

database_proxy = peewee.Proxy()

class BaseModel(peewee.Model):
    class Meta:
        database = database_proxy

class StaticTable(BaseModel):
    foo = peewee.DoubleField()

def Factory(fields):
    class DynamicTable(BaseModel):
        ref = peewee.ForeignKeyField(StaticTable)
    for field in fields:
        peewee.DoubleField().add_to_class(DynamicTable, field)
    return DynamicTable 

def Test(fname, fields):
    db = peewee.SqliteDatabase(fname)
    database_proxy.initialize(db)
    db.create_table(StaticTable)
    dyntable = Factory(fields)
    db.create_table(dyntable)
    db.close()


Test(':memory:', ['foo', 'bar'])
Test(':memory:', ['foo', 'bar', 'extra'])
Run Code Online (Sandbox Code Playgroud)

col*_*fer 5

我认为这突出了 peewee 中的一个错误,您可能明确希望忽略任何反向引用。我已经打开了一张票,并将解决它。

https://github.com/coleifer/peewee/issues/465

同时,您可以通过在模型上设置动态相关名称来消除错误,例如

def Factory(fields):
    dynamic_name = '_'.join(fields)
    class DynamicTable(BaseModel):
        ref = peewee.ForeignKeyField(StaticTable, related_name=dynamic_name)
    for field in fields:
        peewee.DoubleField().add_to_class(DynamicTable, field)
        return DynamicTable
Run Code Online (Sandbox Code Playgroud)

更新:根据 #465 中的修复,现在可以禁用 backref 验证:

def Factory(fields):
    class DynamicTable(BaseModel):
        ref = peewee.ForeignKeyField(StaticTable, related_name=dynamic_name)
        class Meta:
            validate_backrefs = False
    for field in fields:
        peewee.DoubleField().add_to_class(DynamicTable, field)
        return DynamicTable
Run Code Online (Sandbox Code Playgroud)