从外键创建 Django 表单

Create Django Form from ForeignKey

我正在尝试创建一个简单的 Django 应用程序,允许用户创建和编辑包含成分的食谱。

models.py

class Recipe(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)

class Ingredient(models.Model):
    api_id = models.IntegerField(primary_key=True) # id in Spoonacular database 
    name = models.CharField(max_length=100) # human-readable name 
    units = models.CharField(max_length=10) # unit of measure (e.g. 'oz', 'lb'), includes '' for 'number of' 
    amt = models.PositiveIntegerField() # number of units 
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)

我有一个详细视图,显示给定食谱的成分,以及添加和删除成分的按钮。食谱的主键在 URL.

view of detail page with add/remove ingredient buttons

我正在努力做到这一点,以便当用户点击 'Remove Ingredients' 按钮时,它会将他们重定向到一个表单,在该表单中他们可以 select 他们想要的给定食谱中的哪些成分去掉。这是我无法开始工作的部分。据我所知,这需要一个带有查询集的 ModelChoiceField,其中成分的外键与配方的主键匹配 ('recipe_pk')。似乎我需要通过构造函数中的 **kwargs 将给定配方的主键传递到表单中,然后让表单 select 具有适当的成分。但是,当我尝试呈现模板时,这给了我一个 AttributeError 和描述 'tuple' object has no attribute 'get' 。这是一个截图: AttributeError

这是创建此类表单的正确方法吗?如果是,知道哪里出了问题吗?

forms.py

# Trying to create a form where a user can select any number of Ingredients 
#  associated with the Model 

class RemoveIngredientForm(forms.Form):
    to_remove = forms.ModelChoiceField(queryset=Ingredient.objects.all())
    def __init__(self, *args, **kwargs):
        super(RemoveIngredientForm, self).__init__(args, kwargs)
        recipe = Recipe.objects.get(pk=kwargs['recipe_pk'])
        self.fields['to_remove'].queryset = Ingredient.objects.filter(recipe=recipe)
views.py

...

def remove_ingredients(request, **kwargs):
    """
    GET: list of existing ingredients 
    POST: remove selected ingreident from model 
    """
    if request.method == 'POST':
        form = RemoveIngredientForm(request.POST, kwargs=kwargs)
        if form.is_valid():
            picked = form.cleaned_data.get('picked')
            return HttpResponse('How did I get here?') # Haven't gotten to this point yet 

    recipe = Recipe.objects.get(pk=kwargs['recipe_pk']) #'recipe_pk' is the primary key of the Recipe and lives in the URL 
    try: 
        ingredients = Ingredient.objects.filter(recipe=recipe)
    except Ingredient.DoesNotExist: 
        ingredients = None
    form = RemoveIngredientForm(**kwargs)
    context = { 
        'recipe': recipe,
        'form': form
    }
    return render(request, 'food/remove_ingredients.html', context=context)
<!-- food/remove_ingredients.html -->

<h1>Removing ingredients from {{recipe.name}}</h1>
<form method='POST'>
    {{ form.as_p }}
    <input type='submit' value='submit'>
</form>

选择域不起作用,因为它需要一个选择字典。您想要做的是显示特定食谱的成分列表视图,每个成分旁边都有一个删除按钮,该按钮调用该特定成分的删除视图。所以你用食谱的 pk 调用你的 deleteingredients url。然后在您的函数中,您将成分的查询集传递给该食谱 pk 到上下文中。然后在您的模板中使用一个按钮渲染每种成分,该按钮使用该成分的 pk 调用该特定成分的删除。所以根本不需要表格。您只需要另一个删除成分然后重定向到食谱的视图。