[Django]-Django form: erorr passing model foreign into a form choice field

3👍

I’m not an expert on Django. However, I think the problem lies in below code block in forms.py.

   SaleProductName = forms.ModelChoiceField(queryset=Products.objects.all().values_list('ProductName', flat=True))
   SalePartnerName = forms.ModelChoiceField(queryset=Partners.objects.all().values_list('PartnerName', flat=True))

You are trying to insert a string into a ForeignKey field which isn’t possible. Either you would have to change it as below.

   SaleProductName = forms.ModelChoiceField(queryset=Products.objects.all())
   SalePartnerName = forms.ModelChoiceField(queryset=Partners.objects.all())

You can change __str__ method in Product and Partners models to display ‘ProductName’ and ‘PartnerName’ respectively.

    def __str__(self):
        return self.ProductName

Otherwise, you could leave forms.py as it is now handle this in views.py. However, this method would complicate issues if you want use this form for updates as well.

👤dab92

1👍

There are a few issues that you are going to run into with your current setup. If your form would have made it past the error on SaleProductName, it would have errors on multiple other fields as well.

  1. If you want SaleStatus and SalesBroker to have choices, you should set the choices in the model class in models.py and not create those form fields and choices in the form.

    # specifying choices
    
    MY_CHOICES = (
        ("FOO", "foo"),
        ("BAR", "bar"),
    )
    
    # declaring a Model field with choices
    
    class Foo(models.Model):
        bar = models.CharField(
            max_length = 20,
            choices = MY_CHOICES,
            default = 'FOO'
        )
    
  2. I believe your error is due to you creating form fields from the values list of your query but not editing/filtering them as an instance of the model field. If you want to filter a particular form field by the model instance try this:

    class RecordNewDealForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(RecordNewDealForm, self).__init__(*args, **kwargs)
            self.fields['SaleProductName'].queryset = Products.objects.all()
    

Although this queryset is not necessary if you are going to get all values, only if you are wanting to specifically filter the options available for this form field. In reality you could get away with just creating your model form like this(assuming you added the choices to the fields in the model):

class RecordNewDealForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(RecordNewDealForm, self).__init__(*args, **kwargs)

    class Meta:
        model = Sales
        fields = ("SaleID",
                  "SaleProductName","SalePartnerName",
                  "SalePartnerBusinessName",
                  "SaleQuantity",
                  "SaleUnit","SaleNetAmount",
                  "SalePartnerCommission", "SaleDate",
                  "SaleStatus", "SalesBroker"
                  )

To see more about model forms checkout the docs: Django Model Forms

Lastly, this isn’t a problem right now but if this is a record keeping system for sales of products, you have CASCADE set for your foreign key fields.

SaleProductName = models.ForeignKey(Products, on_delete=models.CASCADE)
SalePartnersName = models.ForeignKey(Partners, on_delete=models.CASCADE)  

Meaning if you ever delete that product, or partner, you will also delete all sales record history. A potential better approach would be to set those to PROTECT or RESTRICT, and add boolean field to products or partners to set them to "Active"(True) or "Inactive"(False) to restrict availability and not prevent the corruption of your sales data.

Hope this helps. Cheers.

👤noes1s

Leave a comment