Is there a way to mix formsets and individual input fields and have them validate together.
I have a form that can be represented as a formset but also need an individual FormField whose data must be validated with the formset.
See Cleaning and validating fields that depend on each other. When you’re executing your form’s clean method, you’ve got access to every field in the form, including your formsets.
So I have a formset + 1 individual input field within a form (the same form within which the formset is rendered). But when I print the cleaned data of the form, I get only the formset data. Any reason why I don’t get the individual field value in the form.cleaned_data
?
For us to be able to answer that, we’ll need to see the complete forms and the view involved, including the print statements you’ve added to show cleaned_data
. (We might end up needing to see the template as well, but you don’t need to include that yet - it may not be necessary.)
As a reminder, when you post code snippets, please insert them between lines containing only 3 backticks - ```. (Make sure you use the backtick - ` and not the apostrophe - '.) That means you would have one line with the 3 backticks, your code, and then one more line with just the 3 backticks. That allows this forum software to format your code nicely:
# The line above this is just ```
def function(parm):
return parm
# The line after this is just ```
So, I can’t share the original example due to reasons but here is a minimal one.
views.py
from django.shortcuts import render
from django.views import View
from .forms import ExmapleFormSet
class ExampleView(View):
def get(self, request, *args, **kwargs):
data = { 'form-TOTAL_FORMS': '3', 'form-INITIAL_FORMS': '0', }
example_form = ExmapleFormSet(data)
context = { "example_form": example_form }
return render(request, "base/main.html", context)
def post(self, request, *args, **kwargs):
data = { 'form-TOTAL_FORMS': '3', 'form-INITIAL_FORMS': '0', }
example_form = ExmapleFormSet(data)
if example_form.is_valid():
print(example_form.cleaned_data)
context = { "example_form": example_form }
return render(request, "base/main.html", context)
forms.py
from django import forms
from django.forms import formset_factory, BaseFormSet
class ExampleForm(forms.Form):
sample_field = forms.FloatField(
widget = forms.TextInput(attrs = { "required": "required" })
)
ExmapleFormSet = formset_factory(ExampleForm, extra=3)
main.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Example</title>
</head>
<body>
<h1>Example</h1>
<form method="POST" action="{% url 'example' %}">
{% csrf_token %}
{{ exmaple_form.management_form }}
{% for form in exmaple_form %}
<div>
{{ form.sample_field }}
</div>
{% endfor %}
<input type="text" required id="extra_input" name="extra_input">
<input type="submit" value="Submit">
</form>
</body>
</html>
I am not sure why the formset fields don’t appear. I have perhaps missed something.
So here, there is a formset + one input field, for which I want the data in the example_form.cleaned_data
but I am not sure how that works.
If this is an accurate representation of your files, then you have a typo.
In your view you have:
But in your template you refer to:
(Note: I haven’t looked more closely than this - this is just what jumped out at me.)
Well, that’s an embarrassing mistake. So, now the formset is rendered and now it returns [{'sample_field': 1.0}, {'sample_field': 1.0}, {'sample_field': 1.0}]
which is what I expect from the formset but I don’t get the data entered in the single input field I have put in the form manually.
If this is an accurate representation of your files
Not an accurate example (my version is more involved and hence to separate out the relevant pieces is difficult) but a solution to the minimal example should help me figure out the solution for myself.
You don’t have a form for your additional field.
Review the Working with forms doc for examples, ideas, and information.
Take particular note of the Building a form section, all three parts (the Form class, the view, and the template.)
Keep in mind that you can render multiple forms within the html form tag, and that you need to bind the returned data to the form in your post handler within your view.
So, I have to create a Form
instance for just one input field and then render it along side the formset in the same form ? That seems rather heavy for just 1 input field.
It’s not much heavier than if you did everything “manually”. (Keep in mind all the functionality that the form makes available to you, including appropriate data conversions and validation.)
But really what you would more likely do is make the formset a field within your “base form”, so you’re still only rendering one form. (It just so happens that the formset field is another / embedded form.)
Thanks, this was valuable. I finally got what I wanted working.
Thanks for the tip (and all the tips and advices over the last couple days). Really appreciate it. It’s just that Django has so much built in that it would take a long long time to understand many aspects of it. For example, I did not know you can make embed a formset into another form.
Absolutely agree. I’ve been working seriously with Django for 6 years now, and I’m still learning things about it.
<opinion>
That’s one of the great things about it - you can actually get started knowing very little and produce a usable site. But as you continue to learn more, you realize there’s more you can do with it. </opinion>