Home > database >  How to define a field of a model to have a choice from another field of another model of another app
How to define a field of a model to have a choice from another field of another model of another app

Time:07-05

I have two models defined in two different apps. I want to have a choice option for a particular field in a model, which is deriving those attributes from another field of a model in another app.

eg: I have a model "Inventory" that has a field 'title'.

class Inventory(models.Model):
    title = models.CharField('Title', max_length=120, default='')
    ....

I also have another model 'Invoice' that has a field 'line_one'. Both these models are located in different apps.

class Invoice(models.Model):
   line_one = models.CharField('Line 1', max_length=120)
   ....

I created a Django form for adding the Invoice details. I want a choice option for line_one that has all the values stored in the Inventory.title field so that the user can only select those values from a dropdown menu. How can I implement this? Thanks.

Edit: I referenced line_one to the field title of the Inventory model and it seems to work but it isn't exactly showing the name of the attributes but showing, "Inventory Object(7)", "Inventory Object(8)"

    line_one = models.ForeignKey(Inventory, to_field='title', default=0, on_delete=models.CASCADE)

CodePudding user response:

Use a CharField for line_one

class Inventory(models.Model):
    title = models.CharField('Title', max_length=120, default='')
    # ...


class Invoice(models.Model):
   line_one = models.CharField('Line 1', max_length=120)
   # ...


class InvoiceForm(forms.ModelForm):
    line_one = forms.CharField(widget=forms.Select)

    class Meta:
        model = Invoice
        fields = ['line_one', ] # ...

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

        # populate the choices from the Inventory model objects
        self.fields['line_one'].widget.choices = [(i.title, i.title) for i in Inventory.objects.all()]
        # or
        self.fields['line_one'].widget.choices = [(t,t) for t in Inventory.objects.values_list('title', flat=True)

Use a ForeignKey for line_one

If you like to use a ForeignKey, it is necessary to have unique values for Inventory.title.

class Inventory(models.Model):
    title = models.CharField('Title', max_length=120, default='')
    # ...

    # The __str()__ method of an object is used by django
    # to generate the labels for a Select input widget
    def __str__(self):
        return self.title


class Invoice(models.Model):
   line_one = models.ForeignKey(Inventory, to_field='title', on_delete=models.CASCADE)
   # ...


class InvoiceForm(forms.ModelForm):
    class Meta:
        model = Invoice
        fields = ['line_one', ] # ...

    # no need for any form adjustments,
    # as django uses a select input as default for ForeignKey fields
  • Related