45

Django 1.6

I have a working block of code in a Django form class as shown below. The data set from which I'm building the form field list can include an initial value for any of the fields, and I'm having no success in setting that initial value in the form. The if field_value: block below does indeed populate the initial form dictionary attribute, but the initial value is not being displayed. Note that (in case you are wondering) the .initial attribute does not exist until after the super() call.

Can this be done?

If so, what I'm not doing right to make this work?

Thanks!

def __init__(self, *args, **kwargs):
    id = kwargs.pop('values_id', 0)
    super(LaunchForm, self).__init__(*args, **kwargs)
    # Lotsa code here that uses the id value
    # to execute a query and build the form
    # fields and their attributes from the 
    # result set

    if field_value:
        self.initial[field_name] = field_value
Catskul
  • 17,916
  • 15
  • 84
  • 113
Steve Sawyer
  • 1,785
  • 4
  • 18
  • 21

6 Answers6

42

I had that exact same problem and I solved it doing this:

def __init__(self, *args, **kwargs):
    instance = kwargs.get('instance', None)

    kwargs.update(initial={
        # 'field': 'value'
        'km_partida': '1020'
    })

    super(ViagemForm, self).__init__(*args, **kwargs)

    # all other stuff
24

Try this way:

super(ViagemForm, self).__init__(*args, **kwargs)

if field_value:
    #self.initial[field_name] = field_value
    self.fields[field_name].initial = field_value
biodiv
  • 607
  • 6
  • 16
ndpu
  • 22,225
  • 6
  • 54
  • 69
  • 2
    @ndpu - thanks, but that too doesn't work - the field object exists, and it has a data attribute of "initial" that is indeed set to the initial value, but it's not showing up on the form. @karthikr - the code that establishes the form fields is executed AFTER the super() call, and it isn't until this code executes that I know what the initial values(s) should be. I also tried `self.initial.update({field_name: field_value})' but that also leaves the field blank on the page. I also tried to set the initial field argument as part of the field definition - no success with that approach. – Steve Sawyer Mar 14 '14 at 16:38
  • 2
    Well. i use the exact same code as I have shown in the answer, and it works for me. – karthikr Mar 14 '14 at 21:31
  • @karthikr - My guess is that yours is working because you're calling super() ***after*** setting the property. Things got even more interesting in playing with this on Friday - not only can I verify that the initial value exists, it's also a required field, and the value's presence is causing the form to pass is_valid() in the view's post() method! So, I'm getting the worst of everything - the value is there and is validated, but won't display on the form!! – Steve Sawyer Mar 17 '14 at 14:23
  • I'm no closer to getting this working the way I need it to do so, but I'm making a couple of discoveries, and the failure may not lie with how I'm populating the initial value, but with the behavior of the field type (or my understanding of that behavior). I'm going to post a new topic that gets into this aspect of the issue. Thanks for all your input. – Steve Sawyer Mar 17 '14 at 16:35
  • you have to init the form with ```super``` first to make ```self.fields``` available – biodiv Jun 06 '16 at 08:18
  • I did `super` first and then did the changes and it sets the choice field value to the first choice available. Not working for me – Julio Marins Jul 31 '17 at 19:42
8

I want to mention, although this might not solve your problem, that an 'initial' dict kwarg sent to a form appears to get preference over field['field_name'].initial.

class MyView(View):
    form = MyForm(initial={'my_field': 'first_value'})

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['my_field'].initial = 'second_value'

my_field rendered will have initial set to 'first_value'.

Some options (among others) might be:

Determine second_value in the view before initializing the form:

class MyView(View):
    # determine second_value here
    form = MyForm(initial={'my_field': 'second_value'})

replace first_value with second_value in initial before calling super():

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        # determine second_value here
        if kwargs.get('initial', None):
            kwargs['initial']['my_field'] = 'second_value'
        super().__init__(*args, **kwargs)

Make sure 'first_value' isn't in kwargs['initial'] before calling super():

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        if kwargs.get('initial', None):
            if kwargs['initial']['my_field']
                del(kwargs['initial']['my_field']
        super().__init__(*args, **kwargs)
        # determine second_value here
        self.fields['my_field'].initial = 'second_value'
Megan Word
  • 2,011
  • 1
  • 10
  • 6
0

I had a similar problem setting the initial value for a radio button called 'needs_response' and solved it by inspecting self's attributes and referencing 'declared_fields':

    # views.py
    def review_feedback_or_question(request, template, *args, **kwargs):
        if 'fqid' in kwargs:
            fqid = kwargs['fqid']
        submission = FeedbackQuestion.objects.get(pk=fqid)
        form = FeedbackQuestionResponseForm(submission_type=submission.submission_type)
        # other stuff

    # forms.py
    class FeedbackQuestionResponseForm(forms.Form):
        CHOICES = (('1', 'Yes'), ('2', 'No'))
        response_text = forms.CharField(
            required=False,
            label='',
            widget=forms.Textarea(attrs={'placeholder': 'Enter response...'}))
        needs_response = forms.ChoiceField(choices=CHOICES,
            label='Needs response?',
            widget=forms.RadioSelect())
        def __init__(self, *args, **kwargs):
            if 'submission_type' in kwargs:
                submission_type = kwargs.pop('submission_type')
                if submission_type == 'question':
                    self.declared_fields['needs_response'].initial = 1
                else:
                    self.declared_fields['needs_response'].initial = 2
            super(FeedbackQuestionResponseForm, self).__init__(*args, **kwargs)
Jim
  • 13,430
  • 26
  • 104
  • 155
0

This works:

class BarForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['state'] = forms.ChoiceField(
            required=False,
            choices=Foo.ADDRESS_STATE_CHOICES,
            disabled='disabled',
            initial='xyz',
        )

    state = forms.ChoiceField(
        label='State',
        choices=Foo.ADDRESS_STATE_CHOICES,
        initial='foo',
    )
Julio Marins
  • 10,039
  • 8
  • 48
  • 54
0

Make initial= "" in the field definition will solve your problem. Both proposed methods are correct you need just to define initial= "" in the field definitoion and the problem is solved

David Buck
  • 3,752
  • 35
  • 31
  • 35
Hehe
  • 1
  • 1