Django forms: default values ​​for linked forms

Using this form:

class Form(forms.Form): name = forms.CharField(required=False, initial='Hello world') 

If I do something like this in the view:

 form = Form(request.GET) if form.is_valid(): name = form.cleaned_data['name'] 

Then the initial value of the name is lost, even if request.GET does not contain the name key. Is there a workaround? I would like initial values ​​to work with related forms as "default values".

+4
source share
7 answers

Gently changing Gonzalo's solution, this is the right way:

 class Form(forms.Form): name = forms.CharField(required=False, initial='Hello world') def clean_name(self): if not self['name'].html_name in self.data: return self.fields['name'].initial return self.cleaned_data['name'] 

If you need it, you can watch the django-filter application. I discovered this recently.

+7
source

initial is not really intended to set default values ​​for form fields. Instead, it is really more of a placeholder utility when displaying forms to the user and will not work if the field is not required (for example, in your example).

What you can do is define a clean_<fieldname> method that checks for an empty value for this field and returns the default value:

 class Form(forms.Form): name = forms.CharField(required=False, initial='Hello world') def clean_name(self): name = self.cleaned_data['name'] if name is None: return self.fields['name'].initial return name 
+5
source

I use the following template to set default values ​​as initial values ​​for the form -

 class InitialDefaultForm(forms.Form): def clean(self): cleaned_data = super(InitialDefaultForm, self).clean() # if data is not provided for some fields and those fields have an # initial value, then set the values to initial value for name in self.fields: if not self[name].html_name in self.data and self.fields[name].initial is not None: cleaned_data[name] = self.fields[name].initial return cleaned_data 

This ensures that all fields that have an initial value and do not receive a value from the user are populated with their initial value.

+4
source

Will this work:

 initial_form_data = {'name': 'Hello World'} #put all the initial for fields in this dict initial_form_data.update(request.GET) #any field available in request.GET will override that field in initial_form_data form = Form(initial_form_data) if form.is_valid(): name = form.cleaned_data['name'] 
+2
source

request.GET - the dictionary as an object.

initial only works in the case of an unrelated form.

Forms have an attribute called data . This attribute is provided as the first positional argument or as an argument to the data keyword during form initialization.

Linked forms are those in which you provide some data as the first argument of the form, and the unbound form has the data attribute set to None.

Here, in your form initialization form=Form(request.GET) , you provide the first positional argument, so the data attribute is set on the form and becomes the associated form. This happens even if request.GET is an empty dictionary. And since your form becomes a linked form, therefore, the initial name field does not affect it.

So, in a GET request, you should either do:

 form = Form() 

and the initial of name field will be executed.

Or, if you want to read name with request.GET, and if you need to use it instead of the original one, then your view has the following.

 name = request.GET.get(name) form_level_initial = {} if name: form_level_initial['name'] = name form = Form(initial=form_level_initial) 
+1
source

None of the answers actually do what clime asked about. So here is my solution for the same problem:

 class LeadsFiltersForm(forms.Form): TYPE_CHOICES = Lead.TYPES SITE_CHOICES = [(site.id, site.name) for site in Site.objects.all()] type = forms.MultipleChoiceField( choices=TYPE_CHOICES, widget=forms.CheckboxSelectMultiple(), required=False ) site = forms.MultipleChoiceField( widget=forms.CheckboxSelectMultiple(), required=False, choices=SITE_CHOICES ) date_from = forms.DateField(input_formats=['%m-%d-%Y',], required=False, widget=forms.TextInput(attrs={'placeholder': 'Date From'}), initial=timezone.now() - datetime.timedelta(days=30)) date_to = forms.DateField(input_formats=['%m-%d-%Y',], required=False, widget=forms.TextInput(attrs={'placeholder': 'Date To'})) defaults = { 'type': [val[0] for val in TYPE_CHOICES], 'site': [val[0] for val in SITE_CHOICES], 'date_from': (timezone.now() - datetime.timedelta(days=30)).strftime('%m-%d-%Y'), 'date_to': timezone.now().strftime('%m-%d-%Y') } def __init__(self, data, *args, **kwargs): super(LeadsFiltersForm, self).__init__(data, *args, **kwargs) self.data = self.defaults.copy() for key, val in data.iteritems(): if not data.get(key): continue field = self.fields.get(key) if field and getattr(field.widget, 'allow_multiple_selected', False): self.data[key] = data.getlist(key) else: self.data[key] = data.get(key) 
0
source

The proposed solutions either did not work for me, or simply seemed not very elegant. The documentation states that the initial does not work for the linked form, which is apparently the original question (and mine):

This is why the initial values ​​are displayed only for unrelated forms. For linked forms, HTML output will use linked data.

https://docs.djangoproject.com/en/1.10/ref/forms/fields/#initial

My solution is to see if the form should be connected or not:

 initial = {'status': [Listing.ACTIVE], 'min_price': 123} # Create default options if request.method == 'GET': # create a form instance and populate it with data from the request: if len(request.GET): form = ListingSearchForm(request.GET) # bind the form else: form = ListingSearchForm(initial=initial) # if GET is empty, use default form 

You can also use other ways to initialize the form (see above).

0
source

All Articles