Question

All,

Is there a straightforward way for me to display a form that uses a modelchoicefield for models that have yet to be saved?

class Foo(models.Model):
  name = models.CharField(max_length=42)

class Bar(models.Model):
  name = models.CharField(max_length=42)
  foo = models.ForeignKey("Foo",blank=True,null=True)

class BarForm(ModelForm):
  class Meta:
    model = Bar
  pass

def create_new_bar(request):
  foos = [Foo(name='foo1'), Foo(name='foo2'), Foo(name='foo3')]
  bar = Bar(name='bar',foo=foos[0])
  form = BarForm(instance=bar)
  return render_to_response('bar_template.html',{"form" : form},context_instance=RequestContext(request))

But the "select" widget that gets rendered in the form has empty content. Presumably, this is because there is nothing to bind the queryset to for the ModelChoiceField that Bar's ForeignKey to Foo uses. (Since nothing in "foos" has been saved and therefore does not exist in the database).

Is there another way to deal with this besides writing a custom formfield/widget?

Thanks.

Was it helpful?

Solution

You can add additional field to BarForm with predefined choices - fooempty for example. That field will be shown in case if Foo table is empty. Try this (not tested):

class BarForm(ModelForm):
  FOO_CHOICES = (
    (0, 'Choice1'),
    (1, 'Choice2'),
    (2, 'Choice3'),
  )
  fooempty = forms.ChoiceField(required=False, label='lbl', choices=FOO_CHOICES)
  class Meta:
    model = Bar

  def __init__(self, *args, **kwargs):
    super(BarForm, self).__init__(*args, **kwargs)
    if self.fields['foo'].queryset.count(): # Foo empty?
      self.fields['fooempty'].widget = forms.HiddenInput()
    else:
      self.emptyflag
      self.fields['foo'].widget = forms.HiddenInput() 

  def save(self, commit=True):
    bar = super(BarForm, self).save(commit=False)
    if self.emptyflag:
      bar.foo_id = self.cleaned_data['fooempty']
    bar.save()
    return bar

OTHER TIPS

EDIT: actually, now that I think about it. Those Foos won't have pks. So there is no way that could ever work. The form needs to know the pk of the Foos. You really just need to save them first. How would django know which one is which when it posts back the form? IGNORE ANSWER BELOW.

I think you can change the choices variable on the field. You will need to that in the form. So pass the list of Foos to the init of the form. Something like this:

class BarForm(ModelForm):
    class Meta:
        model = Bar

    def __init__(self, foo_list, *args, **kwargs):
        super(BarForm, self).__init__(*args, **kwargs)

        self.fields['foo'].choices = foo_list

Then in the view:

foos = [Foo(name='foo1'), Foo(name='foo2'), Foo(name='foo3')]
bar = Bar(name='bar', foo=foos[0])
form = BarForm(foos, instance=bar)

I know I've done something like this before. I just can't remember the exact way. Something like this approach should work though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top