python - 在父工厂上存储 factory-boy RelatedFactory 对象
问题描述
我有两个相互包含s 的Django 模型 (Customer
和)。我正在使用 factory-boy 来管理这些模型的创建,并且无法将子工厂实例保存到父工厂(使用使用类定义的关系)。CustomerAddress
ForeignKey
RelatedFactory
我的两个模型:
class ExampleCustomerAddress(models.Model):
# Every customer mailing address is assigned to a single Customer,
# though Customers may have multiple addresses.
customer = models.ForeignKey('ExampleCustomer', on_delete=models.CASCADE)
class ExampleCustomer(models.Model):
# Each customer has a single (optional) default billing address:
default_billto = models.ForeignKey(
'ExampleCustomerAddress',
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name='+')
我有两个工厂,每个型号一个:
class ExampleCustomerAddressFactory(factory.django.DjangoModelFactory):
class Meta:
model = ExampleCustomerAddress
customer = factory.SubFactory(
'ExampleCustomerFactory',
default_billto=None) # Set to None to prevent recursive address creation.
class ExampleCustomerFactory(factory.django.DjangoModelFactory):
class Meta:
model = ExampleCustomer
default_billto = factory.RelatedFactory(ExampleCustomerAddressFactory,
'customer')
创建 aExampleCustomerFactory
时,default_billto
是None,即使 aExampleCustomerAddress
已经创建:
In [14]: ec = ExampleCustomerFactory.build()
In [15]: ec.default_billto is None
Out[15]: True
(使用时create()
,数据库中存在一个新ExampleCustomerAddress
的。我build()
这里使用是为了简化示例)。
按预期创建ExampleCustomerAddress
作品,Customer
并自动创建:
In [22]: eca = ExampleCustomerAddressFactory.build()
In [23]: eca.customer
Out[23]: <ExampleCustomer: ExampleCustomer object>
In [24]: eca.customer.default_billto is None
Out[24]: True <-- I was expecting this to be set to an `ExampleCustomerAddress!`.
我觉得我在这里要疯了,错过了一些非常简单的东西。我得到的印象是我遇到了这个错误,因为这两个模型是如何相互包含ForeignKeys
的。
解决方案
首先,一个简单的经验法则:当你关注 a 时ForeignKey
,总是更喜欢 a SubFactory
;RelatedFactory
旨在遵循相反的关系。
让我们依次看看每个工厂。
ExampleCustomerAddressFactory
当我们在没有客户的情况下调用这家工厂时,我们将希望获得一个与客户相关联的地址,并将其用作该客户的默认地址。
但是,当我们与客户通话时,请不要更改它。
以下将起作用:
class ExampleCustomerAddressFactory(factory.django.DjangoModelFactory):
class Meta:
model = ExampleCustomerAddress
# Fill the Customer unless provided
customer = factory.SubFactory(
ExampleCustomerFactory,
# We can't provide ourself there, since we aren't saved to the database yet.
default_billto=None,
)
@factory.post_generation
def set_customer_billto(obj, create, *args, **kwargs):
"""Set the default billto of the customer to ourselves if empty"""
if obj.customer.default_billto is None:
obj.customer.default_billto = obj
if create:
obj.customer.save()
在这里,我们将新创建的客户价值设置为“我们”;请注意,此逻辑也可以移至ExampleCustomerAddress.save()
.
ExampleCustomerFactory
对于这个工厂,规则更简单:创建客户时,创建一个默认帐单地址(除非已提供值)。
class ExampleCustomerFactory(factory.django.DjangoModelFactory):
class Meta:
model = ExampleCustomer
# We can't use a SubFactory here, since that would be evaluated before
# the Customer has been saved.
default_billto = factory.RelatedFactory(
ExampleCustomerAddressFactory,
'customer',
)
该工厂将按如下方式运行:
- 用;创建
ExampleCustomer
实例default_billto=None
ExampleCustomerAddressFactory(customer=obj)
与新创建的客户通话;ExampleCustomerAddress
该工厂将与该客户创建一个;- 然后,该工厂中的后生成挂钩将检测到客户没有
default_billto
,并将覆盖它。
笔记
- 我没有对此进行测试,因此可能会出现一些拼写错误或小错误;
- 由您决定首先声明哪个工厂,使用目标工厂的路径而不是直接引用;
- 如上所述,当客户的默认帐单地址为空并将地址添加到该客户时,设置该客户的默认帐单地址的逻辑可以移动到模型的
.save()
方法中。
推荐阅读
- c# - .NET - c# - 需要跨分区查询,但禁用文档数据访问问题
- go - splitsh / lite:在 Windows 10 上构建时出错
- django - Django 搜索返回“找不到页面 (404) 错误
- javascript - react-redux 搜索过滤器的问题
- r - Data.table 单线程警告
- c# - VS Code / OmniSharp failing to load project; Can't find a package that is present
- javascript - 如何从文本框中获取输入并使用它在 Google 地图上搜索位置?
- python - 将 numpy 数组扩展到 n*length 并复制其元素的有效方法?
- javascript - Next.js 无法在 HOC 中获取异步数据
- matlab - 平均信号总和