Limiting choices from an intermediary ManyToMany junction table in Django
- by Matthew Rankin
Background
I've created three Django models—Inventory, SalesOrder, and Invoice—to model items in inventory, sales orders for those items, and invoices for a particular sales order. Each sales order can have multiple items, so I've used an intermediary junction table—SalesOrderItems—using the through argument for the ManyToManyField. Also, partial billing of a sales orders is allowed, so I've created a ForeignKey in the Invoice model related to the SalesOrder model, so that a particular sales order can have multiple invoices.
Here's where I deviate from what I've normally seen. Instead of relating the Invoice model to the Item model via a ManyToManyField, I've related the Invoice model to the SalesOrderItem intermediary junction table through the intermediary junction table InvoiceItem. I've done this because it better models reality—our invoices are tied to sales orders and can only include items that are tied to that sales order as opposed to any item in inventory. I will admit that it does seem strange having the intermediary junction table of a ManyToManyField related to the intermediary junction table of another ManyToManyField.
Question
How can I limit the choices available for the invoice_items in the Invoice model to just the sales_order_items of the SalesOrder model for that particular Invoice? (I tried using limit_choices_to= {'sales_order': self.invoice.sales_order}) as part of the item = models.ForeignKey(SalesOrderItem) in the InvoiceItem model, but that didn't work.
Am I correct in thinking that limiting the choices for the invoice_items should be handled in the model instead of in a form?
Code
class Item(models.Model):
item_num = models.SlugField(unique=True)
default_price = models.DecimalField(max_digits=10, decimal_places=2,
blank=True, null=True)
class SalesOrderItem(models.Model):
item = models.ForeignKey(Item)
sales_order = models.ForeignKey('SalesOrder')
unit_price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.DecimalField(max_digits=10, decimal_places=4)
class SalesOrder(models.Model):
customer = models.ForeignKey(Party)
so_num = models.SlugField(max_length=40, unique=True)
sales_order_items = models.ManyToManyField(Item,
through=SalesOrderItem)
class InvoiceItem(models.Model):
item = models.ForeignKey(SalesOrderItem)
invoice = models.ForeignKey('Invoice')
unit_price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.DecimalField(max_digits=10, decimal_places=4)
class Invoice(models.Model):
invoice_num = models.SlugField(max_length=25)
sales_order = models.ForeignKey(SalesOrder)
invoice_items = models.ManyToManyField(SalesOrderItem,
through='InvoiceItem')