factory_boy:添加几个依赖对象

时间:2014-02-04 22:27:32

标签: python django factory-boy

我正在使用factory_boy替换Django应用中的灯具。我有一个产品型号应该有很多优惠和商家。

#models.py
class Product(models.Model):
    name = models.CharField()

class Merchant(models.Model):
    product = models.ForeignKey(Product)
    name = models.CharField()

class Offer(models.Model):
    product = models.ForeignKey(Product)
    price = models.DecimalField(max_digits=10, decimal_places=2)

我想要一家工厂,创建一个包含多个商家和多个商品的产品。

#factories.py
import random
from models import Offer, Merchant, Product

class OfferFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Offer

    product = factory.SubFactory(ProductFactory)
    price = random.randrange(0, 50000, 1)/100.0


class MerchantFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Merchant

    product = factory.SubFactory(ProductFactory)
    name = factory.Sequence(lambda n: 'Merchant %s' % n)
    url = factory.sequence(lambda n: 'www.merchant{n}.com'.format(n=n))

 class ProductFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Product 

    name = "test product"
    offer = factory.RelatedFactory(OfferFactory, 'product')
    offer = factory.RelatedFactory(OfferFactory, 'product') # add a second offer
    offer = factory.RelatedFactory(OfferFactory, 'product') # add a third offer
    merchant = factory.RelatedFactory(MerchantFactory, 'product')
    merchant = factory.RelatedFactory(MerchantFactory, 'product') # add a second merchant
    merchant = factory.RelatedFactory(MerchantFactory, 'product') # add a third merchant

但是当我使用ProductFactory创建产品时,它只有一个商品和一个商家。

In [1]: from myapp.products.factories import ProductFactory

In [2]: p = ProductFactory()

In [3]: p.offer_set.all()
Out[3]: [<Offer: $39.11>]

如何设置ProductFactory以拥有多个特定类型的从属?

3 个答案:

答案 0 :(得分:4)

能够指定父工厂中相关对象的数量:

models.py

class Company(models.Model):
    name = models.CharField(max_length=255)


class ContactPerson(models.Model):
    name = models.CharField(max_length=255)
    company = models.ForeignKey(Company, on_delete=CASCADE, related_name='contacts')

factories.py

class CompanyFactory(factory.django.DjangoModelFactory):
    name = factory.Faker('company')

    class Meta:
        model = Company

    @factory.post_generation
    def add_contacts(self, create, how_many, **kwargs):
        # this method will be called twice, first time how_many will take the value passed
        # in factory call (e.g., add_contacts=3), second time it will be None
        # (see factory.declarations.PostGeneration#call to understand how how_many is populated)
        # ContactPersonFactory is therefore called +1 times but somehow we get right amount of objs
        at_least = 1
        if not create:
            return
        for n in range(how_many or at_least):
            ContactPersonFactory(contact=self)



class ContactPersonFactory(factory.django.DjangoModelFactory):
    name = factory.Faker('first_name')

    class Meta:
        model = ContactPerson

tests.py

company = CompanyFactory(company_name='ACME ltd', add_contacts=4)
print(repr(company.name), len(company.contacts.all()))
company = CompanyFactory(company_name='ACME ltd')
print(repr(company.name), len(company.contacts.all()))

---
'ACME ltd' 4
'ACME ltd' 1

如果你总是只有一个孩子,the docs solution效果很好:

models.py

class CompanyFactory(factory.django.DjangoModelFactory):
    name = factory.Faker('company')
    whatever_really = factory.RelatedFactory('my_app.factories.ContactPersonFactory', 'contact')

    class Meta:
        model = Company

注意相关工厂的完整路径。

tests.py

company = CompanyFactory(company_name='ACME ltd')
print(repr(company.name), len(company.contacts.all()))
---
'ACME ltd' 1

使用的版本

$ pip freeze | egrep 'factory|Faker|Django'
Django==2.0.4
factory-boy==2.10.0
Faker==0.8.13
$ python -V
Python 3.6.5

答案 1 :(得分:1)

试试这个:

class ProductFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Product 

    name = "test product"

    @classmethod
    def create(cls, **kwargs):
        num = kwargs.pop('offer_num', 1)
        attrs = cls.attributes(create=True, extra=kwargs)
        product = cls._generate(True, attrs)
        for n in range(num)
            OfferFactory(product=product)
        return product

ProductFactory(offer_num = 4)这将创建4个相关的优惠。

答案 2 :(得分:0)

这肯定会有效:

class ProductFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Product 

    name = "test product"
    offer1 = factory.RelatedFactory(OfferFactory, 'product')
    offer2 = factory.RelatedFactory(OfferFactory, 'product') # add a second offer
    offer3 = factory.RelatedFactory(OfferFactory, 'product') # add a third offer
    merchant1 = factory.RelatedFactory(MerchantFactory, 'product')
    merchant2 = factory.RelatedFactory(MerchantFactory, 'product') # add a second merchant
    merchant3 = factory.RelatedFactory(MerchantFactory, 'product') # add a third"