Free-form input for ForeignKey Field on a Django ModelForm

后端 未结 4 468
夕颜
夕颜 2021-02-03 09:52

I have two models related by a foreign key:

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

class TestModel(mod         


        
相关标签:
4条回答
  • 2021-02-03 10:30

    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.

    0 讨论(0)
  • 2021-02-03 10:31

    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.

    0 讨论(0)
  • 2021-02-03 10:32

    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')
    
    0 讨论(0)
  • 2021-02-03 10:37

    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)
    
    0 讨论(0)
提交回复
热议问题