Отношение многие ко многим в factory_boy?
Я пытаюсь проверить отношение многих ко многим между двумя моделями Django, используя factory_boy. Документация factory_boy, по-видимому, не обсуждает это, и мне трудно понять, что я делаю неправильно. Когда я запускаю первый тест, я получаю сообщение об ошибке "AttributeError: у объекта" Пицца "нет атрибута" топпинг "". Я получаю похожую ошибку для второго теста.
Когда я запускаю тесты в отладчике, я вижу объект "toppings", но он не понимает, как получить из него имя. Правильно ли я определил метод _prepare в PizzaFactory? Как получить доступ к имени в одной таблице из другой таблицы, когда у вас есть отношение многие ко многим?
Благодарю.
models.py:
from django.db import models
class Topping(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Pizza(models.Model):
name = models.CharField(max_length=100)
toppings = models.ManyToManyField(Topping)
def __unicode__(self):
return self.name
factories.py:
import factory
from models import Topping, Pizza
class ToppingFactory(factory.Factory):
name = 'mushrooms'
class PizzaFactory(factory.Factory):
name = 'Vegetarian'
@classmethod
def _prepare(cls, create, **kwargs):
topping = ToppingFactory()
pizza = super(PizzaFactory, cls)._prepare(create, **kwargs)
pizza.toppings.add(topping)
return pizza
tests.py
from django.test import TestCase
import factory
from app.models import Topping, Pizza
from app.factories import ToppingFactory, PizzaFactory
class FactoryTestCase(TestCase):
def test_pizza_has_mushrooms(self):
pizza = PizzaFactory()
self.assertTrue(pizza.topping.name, 'mushrooms')
def test_mushrooms_on_pizza(self):
topping = ToppingFactory()
self.assertTrue(topping.pizza.name, 'Vegetarian')
2 ответа
Я считаю, что вам нужно использовать @factory.post_generation
декоратор:
class PizzaFactory(factory.Factory):
name = 'Vegetarian'
@factory.post_generation
def toppings(self, create, extracted, **kwargs):
if not create:
# Simple build, do nothing.
return
if extracted:
# A list of groups were passed in, use them
for topping in extracted:
self.toppings.add(topping)
Тогда вы бы назвали это в tests.py pizza = PizzaFactory.create(toppings=(topping1, topping2, tooping3))
С https://factoryboy.readthedocs.org/en/latest/recipes.html.
Просто используйте миксер вместо:
from mixer.backend.django import mixer
# Generate toppings randomly
pizza = mixer.blend(Pizza, toppings=mixer.RANDOM)
# Set toppings
toppings = mixer.cycle(3).blend(Topping)
pizza = mixer.blend(Pizza, toppings=toppings)
# Generate toppings with name=tomato
pizze = mixer.blend(Pizza, toppings__name='tomato')
Легко, настраиваемо, быстрее, без схемы, декларативно, и вы получаете в некоторых тестах то, что вы хотите.