Aaron McCommon
Aaron McCommon

Reputation: 665

django form is returning None even if something is in the input

Hello so I've been creating a custom form int django and everything has been working the way I thought it would until i came across this problem. So I've created a form for instructions:

class InstructionForm(forms.Form):
    step = forms.IntegerField(widget=forms.HiddenInput(attrs={'value':1}))
    instruction = forms.CharField(widget=forms.Textarea)

Which I created a Formset for so I can let the user add as many as they want.

view.py

def create(request):
    recipeForm = RecipeForm()
    ingredientFormSet = formset_factory(IngredientForm, extra=4)
    instructionFormSet = formset_factory(InstructionForm)

    if request.method == "POST":
        recipe = RecipeForm(request.POST)
        ingredients_forms = ingredientFormSet(request.POST, prefix="ingredient")
        instruction_forms = instructionFormSet(request.POST, prefix="instruction")

        if recipe.is_valid() and ingredients_forms.is_valid() and instruction_forms.is_valid():
            newRecipe = Recipe()
            newRecipe.title = recipe.cleaned_data['title']
            newRecipe.description = recipe.cleaned_data['description']
            newRecipe.save()

            for ingredient in ingredients_forms:
                cd = ingredient.cleaned_data
                ingredientName = cd.get('ingredient')
                try:
                    ingredientObj = Ingredient.objects.get(name=str(ingredientName))
                except Ingredient.DoesNotExist:
                    ingredientObj = Ingredient(name=str(ingredientName))
                finally:
                    ingAmount = IngredientAmount()
                    ingAmount.amount = cd.get('amount')
                    ingAmount.unit = cd.get('unit')

                    ingredientObj.save()

                    ingAmount.ingredient = ingredientObj
                    ingAmount.recipe = newRecipe
                    ingAmount.save()
                    newRecipe.ingredients.add(ingredientObj)
                    newRecipe.save()
            #used a counter because my initial way of doing this wont work
            i=1
            for instruction in instruction_forms:
                cd = instruction.cleaned_data
                instruct = cd.get('instruction')
                # I feel like the problem is somewhere in here
                instructObj = Instruction(instruction=instruct)
                instructObj.step = i
                instructObj.recipe = newRecipe
                instructObj.save()
                i+=1
else:
    ingredients_forms = ingredientFormSet(prefix="ingredient")
    instruction_forms = instructionFormSet(prefix="instruction")

return render(request, 'foods/createFood.html',{'recipeForm':recipeForm, 'ingredientFormSet': ingredients_forms, 'instructionFormSet': instruction_forms})

so the ingredients form and the recipe form work just fine I can add Ingredients and they'll all be added to the database. But if I add an instruction the first one works all the others won't they return None.

createFood.html

<div class="container" id="foodsPage">

    <form method="POST">
        {% csrf_token %}
        {{recipeForm.as_p}}

        {{ingredientFormSet.management_form}}
        {% for ingredient in ingredientFormSet %}
        <div class="fieldWrapper" id="ingForm0">
            {{ingredient.amount.label_tag}}
            {{ingredient.amount}}
            {{ingredient.unit.label_tag}}
            {{ingredient.unit}}
            {{ingredient.ingredient.label_tag}}
            {{ingredient.ingredient}}
        </div>
        {% endfor %}
        <div id="addMoreIng">
        </div>
            <input type="button" id="addIngredient" onclick="addIngFunction()" value="Add Ingredient">
        </div>


        <div class="instructions">
        <div id="addMoreIns">
         {{instructionFormSet.management_form}}
         {% for instruction in instructionFormSet %}
            {{instruction.step}}
            {{instruction.instruction.label_tag}}
            {{instruction.instruction}}
             </div>
              </div>
         {% endfor %}





         <input type="button" id="addInstruction" onclick="addInsFunction()" value="Add instruction">

         <script>

         function addIngFunction(){
            $('#id_ingredient-TOTAL_FORMS').val(function(i, oldval){
                    oldval
                    var html = '<div class="fieldWrapper" id="ingForm'+oldval+'">'+
            '<label for="id_ingredient-'+oldval+'-amount">Amount:</label>'+
            ' <input type="number" name="ingredient-'+oldval+'-amount" step="any" id="id_ingredient-'+oldval+'-amount" />'+
            ' <label for="id_ingredient-'+oldval+'-unit">Unit:</label>'+
            ' <input type="text" name="ingredient-'+oldval+'-unit" maxlength="3" id="id_form-'+oldval+'-unit" />'+
            ' <label for="id_ingredient-'+oldval+'-ingredient">Ingredient:</label>'+
            ' <input type="text" name="ingredient-'+oldval+'-ingredient" maxlength="100" id="id_ingredient-'+oldval+'-ingredient" />'+
        '</div>'


            $('#addMoreIng').append(html)
                    return ++oldval;
            })
        }

        function addInsFunction(){
            $('#id_instruction-TOTAL_FORMS').val(function(i, oldval){

                    var val = parseInt(oldval)+1
                    var html = '<input type="hidden" name="instruction-'+oldval+'-step" value="'+val+'" id="id_instruction-'+oldval+'-step" />'+
            '<label for="id_instruction-'+oldval+'-instruction">Instruction:</label>'+
            '<textarea name="instruction-'+oldval+'-instruction" cols="40" rows="10" id="id_instruction-'+oldval+'-instruction">'+
'</textarea>'

            $('#addMoreIns').append(html)
                    return ++oldval;
            })
        }
        </script>


        <input type="submit" value="submit recipe">


     </form>

</div>

I can't figure out why any of the added instructions return None. can anyone help me out?

Upvotes: 1

Views: 1567

Answers (1)

stefanw
stefanw

Reputation: 10570

You are closing two divs inside the {% for instruction in instructionFormSet %} but they should be closed outside the loop. I haven't checked it, but this may close more tags when parsed by the browser into the DOM than intended including implicitly the form tag.

This could lead to some inputs not being inside the form anymore (according to browser DOM) and therefore not being submitted by the browser in the POST request. Try fixing your HTML.

Upvotes: 1

Related Questions