在我的应用程序中,我有一个模型,我只知道运行时的列数。使用下面的Factory
之类的函数来创建模型很好地解决了这个问题。但是,如果我多次使用它(可能会有不同的字段),则创建外键ref
会引发异常:
AttributeError: Foreign key: dynamictable.ref related name "dynamictable_set"
collision with foreign key using same related_name.
消息非常清楚,当我在创建外键时设置related_name
参数时,没有错误。
问题:
为什么我第二次不能使用相同的related_name
?我是否还需要重新定义StaticTable
?
是否有更好的方法可以使用动态模型写入多个数据库?
最小,可重复的例子:
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'])
答案 0 :(得分:4)
我认为这突出了peewee中的一个错误,你可能明确地想要忽略任何backrefs。我打开了一张票并将解决它。
https://github.com/coleifer/peewee/issues/465
与此同时,您可以通过在模型上设置动态related_name来消除错误,例如
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
更新:根据#465中的修复,现在可以禁用反射验证:
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
答案 1 :(得分:0)
@coleifer的建议(在他的回答中)效果很好,只要字段列表是唯一的。由于在我的情况下无法保证,我提出了这个稍微复杂的解决方案,其中所有模型类都在工厂中创建:
import peewee
database_proxy = peewee.Proxy()
def orm_factory():
class OrmWrapper:
class BaseModel(peewee.Model):
class Meta:
database = database_proxy
class StaticTable(BaseModel):
foo = peewee.DoubleField()
@classmethod
def dyntable_factory(cls,fields):
class DynamicTable(cls.BaseModel):
ref = peewee.ForeignKeyField(cls.StaticTable)
for field in fields:
peewee.DoubleField().add_to_class(DynamicTable, field)
return DynamicTable
return OrmWrapper
def test(fname, fields):
orm = orm_factory()
db = peewee.SqliteDatabase(fname)
database_proxy.initialize(db)
db.create_table(orm.StaticTable)
dyntable = orm.dyntable_factory(fields)
db.create_table(dyntable)
db.close()
test(':memory:', ['foo', 'bar'])
test(':memory:', ['foo', 'bar'])