In my application I have a model for which I know the number of columns only at runtime. Using a function like Factory
below to create the model solves this issue nicely. However, if I use it multiple times (with potentially varying fields), the creation of the foreign key ref
throws an exception:
AttributeError: Foreign key: dynamictable.ref related name "dynamictable_set"
collision with foreign key using same related_name.
The message is quite clear and when I set the related_name
argument when creating the foreign key there is no error.
Questions:
Why can't I use the same related_name
the second time? Do I need to redefine StaticTable
as well?
Is there a better approach to write to multiple databases with dynamic models?
Minimal, reproducable example:
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'])
I think this highlights a bug in peewee where you may explicitly want to ignore any backrefs. I've opened a ticket and will resolve it.
https://github.com/coleifer/peewee/issues/465
In the meantime, you can silence the error by setting a dynamic related_name on the model, e.g.
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
Update: per the fix in #465, it's now possible to disable backref validation:
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