djondal
djondal

Reputation: 2541

Initialize a django.forms.ModelChoiceField, bound with a foreign key and a default value

I have a model that contains a foreign key value, then in the form generated from this model as a ModelChoiceField. I want to auto select the user's (update_author). I've tried the below code, using the initial property.

The view creates a formset with the the dates initialized to now() for the empty form. But, I want also the update_author field to be initialized to some value, and it does not work. Even if the dev shell returns the correct user (print), this one is still not selected in the list.

How to initialize a django.forms.ModelChoiceField, binded with foreign key, with a value?


models.py

from django.db import models
import datetime

class Author(models.Model):
    name = models.CharField(max_length=255)
    email = models.CharField(max_length=255)
    def __unicode__(self):
        return self.name


class DataReview(models.Model):
    comments = models.CharField(max_length=255)
    update_author = models.ForeignKey('Author')
    creation_date = models.DateTimeField('date data review created')
    update_date = models.DateTimeField('date review modified')

    def __unicode__(self):
        return "%s" % (self.comments)

forms.py corrected

from bamboo.followup.models import *
from django import forms
from django.forms import ModelForm,Form
from django.forms.extras.widgets import SelectDateWidget
import datetime


class DataReviewForm(ModelForm):


    def __init__(self, *args, **kwargs):
         initial = {
               'update_date': datetime.datetime.now(),
               'creation_date': datetime.datetime.now(),
               'update_author': 1 # not Author.objects.get(id=1)
              }
        if kwargs.has_key('initial'):
            kwargs['initial'].update(initial)
        else:
            kwargs['initial'] = initial
        # Initializing form only after you have set initial dict
        super(DataReviewsForm,self).__init__(*args, **kwargs)
        self.fields['update_date'].widget.attrs['disabled']=''
        self.fields['creation_date'].widget.attrs['disabled']=''
    self.fields['update_author'].widget.attrs['disabled'] = ''

    class Meta:
        model = DataReview

views.py updated

def review(request):
    DataReviewsFormSet = modelformset_factory(DataReview, form=DataReviewsForm)
    if request.method == 'POST':
        formset = DataReviewSet(request.POST)
        if formset.is_valid():
            # do something with the formset.cleaned_dat
            print 'YOUHOU!'
    else:
        formset = DataReviewSet()
    return render_to_response('followup/runs.html', {
        "formset": formset,
        })

Upvotes: 0

Views: 5504

Answers (1)

simplyharsh
simplyharsh

Reputation: 36393

For the core of your question is, as to how to set initial value for ForeignKey field, check the code snippet below.

Note that when you provide initial value to a ForeignKey field, you don't need to pass the object. Pass it the id/pk of that object, and your problem will be solved.

initial = {
           'update_date': datetime.datetime.now(),
           'creation_date': datetime.datetime.now(),
           'update_author': 1 # not Author.objects.get(id=1)
          }
if kwargs.has_key('initial'):
    kwargs['initial'].update(initial)
else:
    kwargs['initial'] = initial
# Initializing form only after you have set initial dict
super(DataReviewsForm,self).__init__(*args, **kwargs)

self.fields['update_date'].widget = forms.HiddenInput()
self.fields['creation_date'].widget = forms.HiddenInput()
self.fields['update_author'].widget = forms.HiddenInput()

A lot cleaner way to do it.

Disabling the fields As Form exposes 'fields widgets' only after invoking constructor, any updation [be it widget override, or changing attributes of widget], can be done only after that. Or, you can do it in form field definition, which doesn't apply on your case. In short, disabling the field is better after super constructor call.

Upvotes: 2

Related Questions