【问题标题】:How to set dynamic many to many in factory boy with through table?如何在带有直通表的工厂男孩中设置动态多对多?
【发布时间】:2016-10-11 10:31:18
【问题描述】:

我在使用直通关系在 factory boy 中与一组 django 模型建立多对多关系时遇到问题。我有一堆食谱和配料。通过设置数量的模型,食谱和成分之间存在多对多关系。我为每种型号都有工厂,但无法将它们连接起来。

简化模型.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)

简化工厂.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

我试过弄乱 factory.RelatedFactory ,但还没有真正做到。理想情况下,我只想能够做到以下几点:

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

这样做虽然不会在任何一方设置多对多关系,而且似乎也无法创建配方配料模型本身。有谁知道这样做的方法吗?

编辑:

我也试过了:

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

但是我无法理解如何使用预先存在的配方和一组成分来创建这些对象。

【问题讨论】:

    标签: django many-to-many factory-boy


    【解决方案1】:

    我刚刚重新创建了这个设置,我正在努力找出问题所在。这里有几个测试证明一切似乎都运行良好?还是我误解了这个问题?

    # 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)
    

    【讨论】:

    • 谢谢!这对我有点帮助——我认为事实上我的连接模型上的保存方法有点混乱,这让我很头疼,我接受这个主要是因为你付出了非凡的努力——谢谢! - 赏金是你的。
    • 我认为 factory-boy 的文档有点误导,用直通表实例化多对多关系的具体说明并没有真正表明你可以像上面那样做,但是在事实上你可以。
    • 不用担心,很高兴它有用:)
    • 刚过来也表示感谢。这是一个完美的例子!
    • 不用担心@Hanny,很高兴它有帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多