I'm using Flask and SQLAlchemy (via the Flask-SQLAlchemy extension) together with Factory_Boy.
My GearItem
model has a foreign key to GearCategory
. Factory_Boy handles this through the SubFactory
function that creates the object to be used as the foreign key in the original factory.
Here are my model definitions:
class GearCategory(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, unique=True, nullable=False)
gear_items = db.relationship('GearItem', backref='category',
lazy='dynamic', order_by='GearItem.name')
class GearItem(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Text, nullable=False, index=True)
category_id = db.Column(db.Integer, db.ForeignKey('gear_category.id'), index=True)
And here are my factory_boy Factory
definitions:
class GearCategoryFactory(BaseFactory): # Based on factory.alchemy.SQLAlchemyModelFactory
class Meta:
model = gear_models.GearCategory
name = factory.LazyAttribute(lambda n: faker.word())
class GearItemFactory(BaseFactory):
class Meta:
model = gear_models.GearItem
name = factory.LazyAttribute(lambda n: faker.word())
category_id = factory.SubFactory(GearCategoryFactory)
I can call GearItemFactory()
with no problems and it's clearly generating both a GearItem
and a parent GearCategory
that's intended to be used as the foreign key.
However, when I call db.session.flush()
, SQLAlchemy doesn't translate the object created by the SubFactory
into an integer that can be used as the foreign key. Instead, it tries to pass the object itself to the underlying database driver, which then complains that has no idea how to handle an object of type GearCategory
.
The error that I'm getting is sqlalchemy.exc.ProgrammingError: (db_driver) can't adapt type 'GearCategory' [SQL: 'INSERT INTO gear_item (...
What am I doing wrong?
The problem is that the GearItemFactory
definition specifies a Python object reference for the foreign key database ID. sqlalchemy
has no problem translating Python objects into database Foreign Key ID. However in my factory I specified an object-to-database column mapping rather than an object-to-object mapping, so SQLAlchemy (rightfully) thinks I want to pass the Python object straight to the database. Just need to change the factory foreign key to an object-to-object mapping and sqlalchemy
will handle the actual database FK column behind the scenes.
This is the broken line:
category_id = factory.SubFactory(GearCategoryFactory)
See how the backref
on GearCategory
is named category
not category_id
?
Updating that line to use category
fixes the problem:
category = factory.SubFactory(GearCategoryFactory)
来源:https://stackoverflow.com/questions/31872497/why-isnt-sqlalchemy-translating-this-object-generated-by-a-factoryboy-subfactor