2
votes

Howdy. I'm working on migrating an internal system to Django and have run into a few wrinkles.

Intro
Our current system (a billing system) tracks double-entry bookkeeping while allowing users to enter data as invoices, expenses, etc.

Base Objects
So I have two base objects/models:

  • JournalEntry
  • JournalEntryItems

defined as follows:

class JournalEntry(models.Model):
    gjID = models.AutoField(primary_key=True)
    date = models.DateTimeField('entry date');
    memo = models.CharField(max_length=100);

class JournalEntryItem(models.Model):

    journalEntryID = models.AutoField(primary_key=True)
    gjID = models.ForeignKey(JournalEntry, db_column='gjID')
    amount = models.DecimalField(max_digits=10,decimal_places=2)

So far, so good. It works quite smoothly on the admin side (inlines work, etc.)

On to the next section.
We then have two more models

  • InvoiceEntry
  • InvoiceEntryItem

An InvoiceEntry is a superset of / it inherits from JournalEntry, so I've been using a OneToOneField (which is what we're using in the background on our current site). That works quite smoothly too.

class InvoiceEntry(JournalEntry):
    invoiceID = models.AutoField(primary_key=True, db_column='invoiceID', verbose_name='')
    journalEntry = models.OneToOneField(JournalEntry, parent_link=True, db_column='gjID')
    client = models.ForeignKey(Client, db_column='clientID')

    datePaid = models.DateTimeField(null=True, db_column='datePaid', blank=True, verbose_name='date paid')

Where I run into problems is when trying to add an InvoiceEntryItem (which inherits from JournalEntryItem) to an inline related to InvoiceEntry. I'm getting the error:

<class 'billing.models.InvoiceEntryItem'> has more than 1 ForeignKey to <class 'billing.models.InvoiceEntry'>

The way I see it, InvoiceEntryItem has a ForeignKey directly to InvoiceEntry. And it also has an indirect ForeignKey to InvoiceEntry through the JournalEntry 1->M JournalEntryItems relationship.

Here's the code I'm using at the moment.

class InvoiceEntryItem(JournalEntryItem):
    invoiceEntryID = models.AutoField(primary_key=True, db_column='invoiceEntryID', verbose_name='')
    invoiceEntry = models.ForeignKey(InvoiceEntry, related_name='invoiceEntries', db_column='invoiceID')
    journalEntryItem = models.OneToOneField(JournalEntryItem, db_column='journalEntryID')
  1. I've tried removing the journalEntryItem OneToOneField. Doing that then removes my ability to retrieve the dollar amount for this particular InvoiceEntryItem (which is only stored in journalEntryItem).

  2. I've also tried removing the invoiceEntry ForeignKey relationship. Doing that removes the relationship that allows me to see the InvoiceEntry 1->M InvoiceEntryItems in the admin inline. All I see are blank fields (instead of the actual data that is currently stored in the DB).

It seems like option 2 is closer to what I want to do. But my inexperience with Django seems to be limiting me. I might be able to filter the larger pool of journal entries to see just invoice entries. But it would be really handy to think of these solely as invoices (instead of a subset of journal entries).

Any thoughts on how to do what I'm after?

2

2 Answers

1
votes

First, inheriting from a model creates an automatic OneToOneField in the inherited model towards the parents so you don't need to add them. Remove them if you really want to use this form of model inheritance.

If you only want to share the member of the model, you can use Meta inheritance which will create the inherited columns in the table of your inherited model. This way would separate your JournalEntry in 2 tables though but it would be easy to retrieve only the invoices.

0
votes
  1. All fields in the superclass also exist on the subclass, so having an explicit relation is unnecessary.
  2. Model inheritance in Django is terrible. Don't use it. Python doesn't need it anyway.