Formset Data Initialization - python

I'm trying to understand how the initialization of formset data works. To create a formset you use formset_factory and define arguments "extra" and "max_num", which determine the number of extra blank forms after the initial/filled forms and the max number of forms posted respectfully. But then, when you create an instance of the defined formset to pass to the template as data, you pass into that instance more data, specifically 'form-TOTAL_FORMS', 'form-INITIAL_FORMS', and 'form-MAX_NUM_FORMS'. But haven't we already defined in the formset_factory the max_num_forms? Why are we defining this twice? For documentation initial forms seems to be just what it sounds--forms already filled in, which is different than "extra". Just don't understand defining the max arg twice.

According to the docs:
You may have noticed the additional data (form-TOTAL_FORMS,
form-INITIAL_FORMS and form-MAX_NUM_FORMS) that was required in the
formset’s data above. This data is required for the ManagementForm.
This form is used by the formset to manage the collection of forms
contained in the formset. If you don’t provide this management data,
an exception will be raised.
https://docs.djangoproject.com/en/2.2/topics/forms/formsets/#understanding-the-managementform

Related

Django form has no errors, but is not valid? [duplicate]

Given an example like this:
class MyForm(forms.Form):
name = forms.CharField()
I'm trying to grasp what the difference between the following two snippets is:
"Bound Data" style:
my_form = MyForm({'name': request.user.first_name})
"Initial data" style:
my_form = MyForm(initial={'name': request.user.first_name})
The documentation seems to suggest than "initial is for dynamic initial values", and yet being able to pass "bound data" to the constructor accomplishes exactly the same thing. I've used initial data in the past for dynamic values, but I'm tempted to use the more straightforward "bound data" style, but would like some insights about what the real difference between these two styles is.
Here's the key part from the django docs on bound and unbound forms.
A Form instance is either bound to a set of data, or unbound:
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
You can't really see the difference for the example form you gave, because the form is valid in the "bound data" style. Let's extend the form by adding an age field, then the difference will be more obvious.
class MyForm(forms.Form):
name = forms.CharField()
age = forms.IntegerField()
Bound form
my_form = MyForm({'name': request.user.first_name})
This form is invalid, because age is not specified. When you render the form in the template, you will see validation errors for the age field.
Unbound form with dynamic initial data
my_form = MyForm(initial={'name':request.user.first_name})
This form is unbound. Validation is not triggered, so there will not be any errors displayed when you render the template.
No, that's not what the difference is (and I'd be interested to know where in the documentation you got that impression from). The difference is whether validation is performed.
Initial data does not trigger validation. This allows you, for example, to pre-fill certain fields but leave others empty, even though they are required. If you used bound data, you would get errors for those empty required fields even on the first viewing of that form, which would be annoying for the user.
Bound data, of course, triggers validation. Also, if you're using a modelform, the related instance will only be updated with bound data, not initial data.
Another difference is that data expects something that widgets can parse whereas initial is per-field. This makes a difference if you e.g. use MultiWidgets. In such case data should contain something like
{'myfield_0': 'data for subwidget 0',
'myfield_1': 'data for subwidget 1'}
whereas initial expects something like this:
{'myfield': 'data for subwidget 0,data for subwidget 1'}

How to add input fields to a form dynamically with custom validator?

I have a form with a few integer fields dynamically added in a view, those fields are for the user to rank from 1-N. I've had trouble figuring out how to write a validator that can ensure reach field.data has a unique value and are from from 1 to N.
I've figured out how to dynamically add fields to a form per wtforms' docs, but I'd like to validate them all against each other like this question and I haven't figured out how to properly reference the dynamic fields in the overridden validate function.
How can I reference the dynamic fields in my form instance in my validator? In the question linked above they do it in the line:
for field in [self.select1, self.select2, self.select3]:
But since I'm adding those fields dynamically with setattr I don't know those field names. I tried adding a list variable to the Form and appending to that list when I add the dynamic fields but they show up as:
<UnboundField(IntegerField, ('first',), {'validators': [<wtforms.validators.DataRequired object at 0x7ff75a6d7390>]})>
Instead of just IntegerFields if I reference a field like select1 in the example above:
<wtforms.fields.core.IntegerField object at 0x7fac1bd54910>
How can I reference and validate together these integer fields that I add to my form dynamically?
Turns out digging a little closer in the WTForms documentation, I should have been using a FieldList. And even better than that I can use a FieldList to enclose a list of FieldForms, this provides some more flexibility for adding fields dynamically.

How to properly validate a MultipleChoiceField in a Django form

I have a MultipleChoiceField representing US states, and passing a GET request to my form like ?state=AL%2CAK results in the error:
Select a valid choice. AL,AK is not one of the available choices.
However, these values are definitely listed in the fields choices, as they're rendered in the form field correctly.
I've tried specifying a custom clean_state() method in my form, to convert the value to a list, but that has no effect. Printing the cleaned_data['state'] seems to show it's not even being called with the data from request.GET.
What's causing this error?
from django import forms
class MyForm(forms.Form):
state = forms.MultipleChoiceField(
required=False,
choices=[('AL','Alabama'),('AK','Alaska')],
)
MultipleChoiceFields don't pass all of the selected values in a list, they pass several different values for the same key instead.
In other words, if you select 'AL' and 'AK' your querystring should be ?state=AL&state=AK instead of ?state=AL%2CAK.
Without seeing your custom clean_state() method I can't tell you what's going wrong with it, but if the state field isn't valid because the querystring is wrong then 'state' won't be in cleaned_data (because cleaned_data only holds valid data).
Hopefully that helps. If you're still stuck try adding a few more details and I can try to be more specific.

Pass an entire inital object in an edit form (data pre-population) in Django

I have a very complicated form and I choose to not use ModelForm since I needed flexibility and control over the fields. Since I am not using ModelForm, I can't simply do something like instance=order, where order = Order.objects.get(pk=1).
Currently I am pre-populating every field with initial in the forms.py as oppose to the views.py like this
self.fields['work_type'] = forms.ChoiceField(choices=Order.WORK_TYPE_CHOICES, initial=order.work_type)
But I was wondering if I could pass the entire order object to a form or do I have to declare initial to every field?
Is there a way to do something like
order_form = OrderEditForm(data=request.POST, initial=order)
in views.py?
I have a very complicated form and I choose to not use ModelForm since
I needed flexibility and control over the fields
Everything that you can do using a Form, you can do in a ModelForm such as adding new fields or over-riding attributes on the fields etc.
But I was wondering if I could pass the entire order object to a form
or do I have to declare initial to every field?
You can pass the order object into the form but you will still have to populate each field individually either in the forms or in the view function.
So in your view you would do something like this:
intial = {'order_number': order.number, 'order_id': order.id}
form = OrderForm(initial=initial)
The easiest way to prepopulate data to a form is passing a dictionary as first argument to de form constructor.
order_form = OrderEditForm(order.__dict__())
where __dict__() is a method that passes "order" object attributes to a dictionary with each attribute's name as a key and their content as value.
An example of how to "invent" such a method could be something like:
order_initial = Order.objects.filter(pk=order.pk).values()[0]
and then construct the form with:
order_form = OrderEditForm(order_initial)
Look at this example (how they populate values at "post" time):
For future reference to other people:
I have since found out after reading SO's comments and answers that it's better to use ModelForm even if you end up explicitly defining every field manually (using something like self.fields['foo'] = forms.CharField()).
In any case, if you are trying to pass a dictionary of current values in a form then the best (built-in) way to convert a model to a dictionary is actually using model_to_dict:
from django.forms.models import model_to_dict
order = Order.objects.get(pk=1)
dictionary = model_to_dict(order)
form = OrderEditForm(dictionary)
I got the solution from this blog. I hope this will be helpful for someone.

Difference between Django Form 'initial' and 'bound data'?

Given an example like this:
class MyForm(forms.Form):
name = forms.CharField()
I'm trying to grasp what the difference between the following two snippets is:
"Bound Data" style:
my_form = MyForm({'name': request.user.first_name})
"Initial data" style:
my_form = MyForm(initial={'name': request.user.first_name})
The documentation seems to suggest than "initial is for dynamic initial values", and yet being able to pass "bound data" to the constructor accomplishes exactly the same thing. I've used initial data in the past for dynamic values, but I'm tempted to use the more straightforward "bound data" style, but would like some insights about what the real difference between these two styles is.
Here's the key part from the django docs on bound and unbound forms.
A Form instance is either bound to a set of data, or unbound:
If it’s bound to a set of data, it’s capable of validating that data and rendering the form as HTML with the data displayed in the HTML.
If it’s unbound, it cannot do validation (because there’s no data to validate!), but it can still render the blank form as HTML.
You can't really see the difference for the example form you gave, because the form is valid in the "bound data" style. Let's extend the form by adding an age field, then the difference will be more obvious.
class MyForm(forms.Form):
name = forms.CharField()
age = forms.IntegerField()
Bound form
my_form = MyForm({'name': request.user.first_name})
This form is invalid, because age is not specified. When you render the form in the template, you will see validation errors for the age field.
Unbound form with dynamic initial data
my_form = MyForm(initial={'name':request.user.first_name})
This form is unbound. Validation is not triggered, so there will not be any errors displayed when you render the template.
No, that's not what the difference is (and I'd be interested to know where in the documentation you got that impression from). The difference is whether validation is performed.
Initial data does not trigger validation. This allows you, for example, to pre-fill certain fields but leave others empty, even though they are required. If you used bound data, you would get errors for those empty required fields even on the first viewing of that form, which would be annoying for the user.
Bound data, of course, triggers validation. Also, if you're using a modelform, the related instance will only be updated with bound data, not initial data.
Another difference is that data expects something that widgets can parse whereas initial is per-field. This makes a difference if you e.g. use MultiWidgets. In such case data should contain something like
{'myfield_0': 'data for subwidget 0',
'myfield_1': 'data for subwidget 1'}
whereas initial expects something like this:
{'myfield': 'data for subwidget 0,data for subwidget 1'}

Categories