Создание формы Django из иностранного ключа

Я пытаюсь создать простое приложение 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.

просмотр страницы деталей с кнопками добавления/удаления ингредиента

Я пытаюсь сделать так, чтобы когда пользователь нажимает на кнопку "Удалить ингредиенты", она перенаправляла его на форму, где он может выбрать, какие ингредиенты из данного рецепта он хочет удалить. Это та часть, которую я не могу заставить работать. Насколько я могу судить, для этого требуется поле ModelChoiceField с набором запросов, где внешний ключ ингредиента совпадает с первичным ключом рецепта ('recipe_pk'). Похоже, что мне нужно передать первичный ключ данного рецепта в форму через **kwargs в конструкторе, а затем заставить форму выбрать соответствующие ингредиенты. Однако это дает мне 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>

Поле выбора не будет работать, потому что ему нужен словарь вариантов. Вы хотите отобразить список ингредиентов для определенного рецепта с кнопкой удаления рядом с каждым ингредиентом, которая вызывает просмотр удаления этого ингредиента. Поэтому вы вызываете функцию deleteingredients url с pk рецепта. Затем в своей функции вы передаете в контекст queryset ингредиентов для этого рецепта pk. Затем в своем шаблоне отобразите каждый ингредиент с кнопкой, которая вызывает delete для этого конкретного ингредиента с пк этого ингредиента. Таким образом, форма не нужна вообще. Вам просто нужно другое представление, которое удаляет ингредиент, а затем перенаправляет на рецепт.

Вернуться на верх