Free-form input for ForeignKey Field on a Django ModelForm

孤人 提交于 2019-12-20 09:59:41

问题


I have two models related by a foreign key:

# models.py    
class TestSource(models.Model):
  name        = models.CharField(max_length=100)

class TestModel(models.Model):
  name        = models.CharField(max_length=100)
  attribution = models.ForeignKey(TestSource, null=True)

By default, a django ModelForm will present this as a <select> with <option>s; however I would prefer that this function as a free form input, <input type="text"/>, and behind the scenes get or create the necessary TestSource object and then relate it to the TestModel object.

I have tried to define a custom ModelForm and Field to accomplish this:

# forms.py
class TestField(forms.TextInput):
  def to_python(self, value):
    return TestSource.objects.get_or_create(name=value)

class TestForm(ModelForm):
  class Meta:
    model=TestModel
    widgets = {
      'attribution' : TestField(attrs={'maxlength':'100'}),
    }

Unfortunately, I am getting: invalid literal for int() with base 10: 'test3' when attempting to check is_valid on the submitted form. Where am I going wrong? Is their and easier way to accomplish this?


回答1:


Something like this should work:

class TestForm(ModelForm):
  attribution = forms.CharField(max_length=100)

  def save(self, commit=True):
      attribution_name = self.cleaned_data['attribution']
      attribution = TestSource.objects.get_or_create(name=attribution_name)[0]  # returns (instance, <created?-boolean>)
      self.instance.attribution = attribution

      return super(TestForm, self).save(commit)

  class Meta:
    model=TestModel
    exclude = ('attribution')



回答2:


There are a few problems here.

Firstly, you have defined a field, not a widget, so you can't use it in the widgets dictionary. You'll need to override the field declaration at the top level of the form.

Secondly get_or_create returns two values: the object retrieved or created, and a boolean to show whether or not it was created. You really just want to return the first of those values from your to_python method.

I'm not sure if either of those caused your actual error though. You need to post the actual traceback for us to be sure.




回答3:


TestForm.attribution expects int value - key to TestSource model.

Maybe this version of the model will be more convenient for you:

class TestSource(models.Model):
    name = models.CharField(max_length=100, primary_key=True)



回答4:


Taken from:

How to make a modelform editable foreign key field in a django template?

class CompanyForm(forms.ModelForm):
s_address = forms.CharField(label='Address', max_length=500, required=False)

def __init__(self, *args, **kwargs):
    super(CompanyForm, self).__init__(*args, **kwargs)
    try:
        self.fields['s_address'].initial = self.instance.address.address1
    except ObjectDoesNotExist:
        self.fields['s_address'].initial = 'looks like no instance was passed in'

def save(self, commit=True):
    model = super(CompanyForm, self).save(commit=False)
    saddr = self.cleaned_data['s_address']
    if saddr:
        if model.address:
            model.address.address1 = saddr
            model.address.save()
        else:
            model.address = Address.objects.create(address1=saddr)
            # or you can try to look for appropriate address in Address table first
            # try:
            #     model.address = Address.objects.get(address1=saddr)
            # except Address.DoesNotExist:
            #     model.address = Address.objects.create(address1=saddr)

    if commit:
        model.save()

    return model

class Meta:
    exclude = ('address',) # exclude form own address field

This version sets the initial data of the s_address field as the FK from self, during init , that way, if you pass an instance to the form it will load the FK in your char-field - I added a try and except to avoid an ObjectDoesNotExist error so that it worked with or without data being passed to the form.

Although, I would love to know if there is a simpler built in Django override.



来源:https://stackoverflow.com/questions/4137196/free-form-input-for-foreignkey-field-on-a-django-modelform

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!