2016-10-11 1 views
2

Je rencontre des problèmes pour établir une relation many-to-many avec un ensemble de modèles django dans factory boy, en utilisant une relation through. J'ai un tas de recettes et d'ingrédients. Il existe une relation plusieurs-à-plusieurs entre les recettes et les ingrédients grâce à un modèle qui définit une quantité. J'ai des usines pour chaque modèle mais je n'arrive pas à les relier.Comment définir dynamique beaucoup à plusieurs dans l'usine garçon avec une table à travers?

simplifié models.py:

class Ingredient(models.Model): 
    name = models.CharField(max_length=40) 

class Recipe(models.Model): 
    name = models.CharField(max_length=128) 
    ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient') 

class RecipeIngredient(models.Model): 
    recipe = models.ForeignKey(Recipe) 
    ingredient = models.ForeignKey(Ingredient) 
    quantity = models.IntegerField(default=1) 

factories.py

class RecipeFactory(factory.django.DjangoModelFactory): 
    class Meta: 
     model = Recipe 

class IngredientFactory(factory.django.DjangoModelFactory): 
    class Meta: 
     model = Ingredient 

class RecipeIngredientFactory(factory.django.DjangoModelFactory): 
    class Meta: 
     model = RecipeIngredient 
    recipe = factory.SubFactory(RecipeFactory) 
    ingredient = factory.SubFactory(IngredientFactory) 
    quantity = 1 

simplifié j'ai essayé de jouer avec factory.RelatedFactory mais n'a pas encore vraiment nulle part. Idéalement, je veux juste être en mesure de faire ce qui suit:

recipe = RecipeFactory(name="recipe1") 
ingredient = IngredientFactory(name="ingredient1") 
ri = RecipeIngredientFactory(recipe=recipe, ingredient=ingredient) 

Faire cela mais ne définit pas le plusieurs à plusieurs de chaque côté, et semble aussi manquer de créer le modèle de recipeingredient lui-même. Est-ce que quelqu'un sait d'une manière de faire ceci?

Edit:

J'ai aussi essayé:

class RecipeWith3Ingredients(RecipeFactory): 
    ingredient1 = factory.RelatedFactory(RecipeIngredientFactory, 'recipe') 
    ingredient2 = factory.RelatedFactory(RecipeIngredientFactory, 'recipe') 
    ingredient3 = factory.RelatedFactory(RecipeIngredientFactory, 'recipe') 

Mais ne peux pas obtenir ma tête comment je crée ces objets avec une recette pré-existante et un ensemble d'ingrédients.

Répondre

2

Je viens de recréer cette configuration et j'ai du mal à voir quel est le problème. Voici plusieurs tests qui démontrent que tout semble bien fonctionner? Ou ai-je mal compris la question?

# create recipe ingredient and recipe ingredient 
recipe = RecipeFactory(name="recipe1") 
ingredient = IngredientFactory(name="ingredient1") 
recipe_ingredient = RecipeIngredientFactory(recipe=recipe, ingredient=ingredient) 

# recipe created?  
r = Recipe.objects.all().first() 
self.assertEqual(r, recipe) 

# ingredient created? 
i = Ingredient.objects.all().first() 
self.assertEqual(i, ingredient) 

# recipe ingredient created? 
ri = RecipeIngredient.objects.all().first() 
self.assertEqual(ri, recipe_ingredient)   

# test many to many 
self.assertEqual(ri, r.recipeingredient_set.all()[0]) 
self.assertEqual(ri, i.recipeingredient_set.all()[0]) 

# add a new ingredient to recipe 1 
ingredient2 = IngredientFactory(name='ingredient2') 
recipe_ingredient2 = RecipeIngredientFactory(recipe=recipe, ingredient=ingredient2) 

# test many to many 
self.assertTrue(recipe_ingredient in r.recipeingredient_set.all()) 
self.assertTrue(recipe_ingredient2 in r.recipeingredient_set.all()) 

# create a pre-existing recipe and a set of ingredients 
pizza_recipe = RecipeFactory(name='Pizza') 
cheese_on_toast_recipe = RecipeFactory(name='Cheese on toast') 

cheese_ingredient = IngredientFactory(name='Cheese') 
tomato_ingredient = IngredientFactory(name='Tomato') 
pizza_base_ingredient = IngredientFactory(name='Pizza base') 
toast_ingredient = IngredientFactory(name='Toast') 

# now put together 
RecipeIngredientFactory(recipe=pizza_recipe, ingredient=cheese_ingredient) 
RecipeIngredientFactory(recipe=pizza_recipe, ingredient=tomato_ingredient) 
RecipeIngredientFactory(recipe=pizza_recipe, ingredient=pizza_base_ingredient) 

RecipeIngredientFactory(recipe=cheese_on_toast_recipe, ingredient=cheese_ingredient)   
RecipeIngredientFactory(recipe=cheese_on_toast_recipe, ingredient=toast_ingredient)   

# test pizza recipe 
pizza_ingredients = [cheese_ingredient, tomato_ingredient, pizza_base_ingredient] 
pr = Recipe.objects.get(name='Pizza') 

for recipe_ingredient in pr.recipeingredient_set.all(): 
    self.assertTrue(recipe_ingredient.ingredient in pizza_ingredients) 

# test cheese on toast recipe 
cheese_on_toast_ingredients = [cheese_ingredient, toast_ingredient] 
cotr = Recipe.objects.get(name='Cheese on toast') 

for recipe_ingredient in cotr.recipeingredient_set.all(): 
    self.assertTrue(recipe_ingredient.ingredient in cheese_on_toast_ingredients) 

# test from ingredients side 
cheese_recipes = [pizza_recipe, cheese_on_toast_recipe] 
ci = Ingredient.objects.get(name='Cheese') 

for recipe_ingredient in ci.recipeingredient_set.all(): 
    self.assertTrue(recipe_ingredient.recipe in cheese_recipes) 
+0

Merci! Cela m'a un peu aidé - je pense en effet que j'avais la méthode de sauvegarde sur mon modèle de jointure un peu mutilé qui me causait des maux de tête, j'accepte ceci cependant principalement pour l'effort extraordinaire que vous avez fait - merci! - La prime est à vous. – bharling

+0

Je pense que les docs pour factory-boy sont un peu trompeurs cependant, les instructions spécifiques pour instancier plusieurs à plusieurs relations avec une table à travers n'indiquent pas vraiment que vous pouvez le faire comme ci-dessus, mais en fait vous pouvez. – bharling

+0

Pas de soucis, content qu'il soit d'une certaine utilité :) – tdsymonds