Python Factory Boy和相关对象的创建

Python Factory Boy和相关对象的创建,python,django,unit-testing,factory,factory-boy,Python,Django,Unit Testing,Factory,Factory Boy,假设这些Django模型是这样关联的: class Service: restaurant = models.ForeignKey(Restaurant) hist_day_period = models.ForeignKey(DayPeriod) class DayPeriod: restaurant = models.ForeignKey(Restaurant) 我想使用工厂创建一个服务对象。它应该创建所有3个模型,但使用相同的餐厅 使用此代码: class Servi

假设这些Django模型是这样关联的:

class Service:
   restaurant = models.ForeignKey(Restaurant)
   hist_day_period = models.ForeignKey(DayPeriod)

class DayPeriod:
   restaurant = models.ForeignKey(Restaurant)
我想使用工厂创建一个
服务
对象。它应该创建所有3个模型,但使用相同的餐厅

使用此代码:

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.SubFactory('restaurants.factories.RestaurantFactory')

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory', restaurant=restaurant)
Factory boy将创建两个不同的餐厅:

s1 = ServiceFactory.create()
s1.restaurant == s1.hist_day_period.restaurant
>>> False

你知道怎么做吗?我不清楚是否应该使用
相关因素
而不是
子工厂
来实现这一点。

我反复讨论了从工厂内部或单独创建相关或FK对象是否有意义。正如您已经发现的,您不一定希望每次调用
ServiceFactory()
时都能找到一家新餐厅。我认为您最好保持它们的简单,而不必使用稍微冗长的调用代码

注释掉
restaurant=factory.SubFactory
行,然后像这样调用您的工厂:

restaurant = Restaurant.objects.get(foo='bar')
ServiceFactory.create_batch(3, restaurant=restaurant)
或者,如果您确实希望使用工厂创建餐厅,但只希望创建一个餐厅:

restaurant = RestaurantFactory()
ServiceFactory.create_batch(3, restaurant=restaurant)

IOTW,让您的工厂尽可能少地进行假设,这样您就可以灵活地从测试或系统的不同部分构建所需的任何数据结构。

您想使用factoryboy和
SelfAttribute

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.SubFactory('restaurants.factories.RestaurantFactory')

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory',
        restaurant=factory.SelfAttribute('..restaurant')
    )
有了这个测试应用程序,我可以

In [1]: from service.tests import ServiceFactory
In [2]: s1 = ServiceFactory.create()
In [3]: s1.restaurant == s1.hist_day_period.restaurant
Out[3]: True

In [4]: s1.restaurant_id
Out[4]: 4

In [5]: s1.hist_day_period.restaurant_id
Out[5]: 4

您可以将
迭代器
与查询集一起使用,而不是使用
子工厂

例如:

class ServiceFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Service

    restaurant = factory.Iterator(models.Restaurant.object.all())

    hist_day_period = factory.SubFactory(
        'day_periods.factories.DayPeriodFactory', restaurant=restaurant)

不过,我不确定在哪家餐厅最好。在我们的代码库中,我覆盖了
DiscoverRunner
,并在那里创建了用于此目的的模型(在
setup\u databases
,感觉像是一个黑客)。

不清楚这如何解决OP创建三个服务记录但只有一个餐厅记录的问题。OP声明“它应该创建所有三个模型,但使用同一个餐厅。”. 我把这读作
服务
餐厅
日间时段
,但只有一家
餐厅
,他提供的代码示例似乎支持了这个很好的答案,我认为在这里提及lazyattribute并解释使用或不使用
RelatedFactory
的原因也很有意义。非常感谢,正是我需要的。你应该得到这份赏金:)嘿,大卫。我在想,这些答案对你有帮助吗?@JohnMoutafis是的:)谢谢@shacker,你的答案帮助我提高了一些高度,我认为你的灵活性是对的。然而,华尔兹的答案正是我想做的事情的技术方法:)