本文介绍了SQLAlchemy为什么不将FactoryBoy子工厂生成的此对象转换为外键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Flask和SQLAlchemy(通过Flask-SQLAlchemy扩展名)以及 Factory_Boy .

I'm using Flask and SQLAlchemy (via the Flask-SQLAlchemy extension) together with Factory_Boy.

我的GearItem模型具有GearCategory的外键. Factory_Boy 通过SubFactory函数处理此问题,该函数在原始对象中创建用作外键的对象工厂.

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.

这是我的模型定义:

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)

这是我的factory_boy Factory定义:

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)

我可以毫无问题地调用GearItemFactory(),并且显然可以生成要用作外键的GearItem和父GearCategory.

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.

但是,当我调用db.session.flush()时,SQLAlchemy不会将SubFactory创建的对象转换为可用作外键的整数.相反,它尝试将对象本身传递给基础数据库驱动程序,该驱动程序随后抱怨说不知道如何处理类型为GearCategory的对象.

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.

我遇到的错误是sqlalchemy.exc.ProgrammingError: (db_driver) can't adapt type 'GearCategory' [SQL: 'INSERT INTO gear_item (...

我在做什么错了?

推荐答案

问题是GearItemFactory定义为外键数据库ID指定了Python对象引用. sqlalchemy将Python对象转换为数据库外键ID没问题.但是,在我的工厂中,我指定了对象到数据库的列映射,而不是对象到对象的映射,因此SQLAlchemy(正确地)认为我想将Python对象直接传递给数据库.只需将工厂外键更改为对象到对象的映射,然后sqlalchemy将在后台处理实际的数据库FK列.

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.

这是虚线:

category_id = factory.SubFactory(GearCategoryFactory)

看看GearCategory上的backref如何命名为category而不是category_id?更新该行以使用category可以解决此问题:

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)

这篇关于SQLAlchemy为什么不将FactoryBoy子工厂生成的此对象转换为外键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 19:30