Helliaca
Helliaca

Reputation: 183

Django - Foreign key referencing one of two tables depending on its content

I've hit a dead end in my database-model design and could use some help. We are using a Postgres database and django framework to store a variety of papers, books etc.

These are the base classes I'm having trouble with:

class Publisher(models.Model):
    name = models.CharField(unique=True)
    website = models.URLField(blank=True)
    #...

class Editor(models.Model):
    firstname = models.CharField()
    lastname = models.CharField()
    #...

class Book(models.Model):
    title = models.CharField(unique=True)
    #...
    editors = models.ManyToManyField(Editor, blank=True)
    publisher = models.ForeignKey(Publisher, blank=True)
    #...

The Editor class above is modeled to store the editor(s) as persons of a corresponding book eg. "Ryan Carey" or "Nicholas Rowe". The Publisher class would hold information like "University of Chicago Press".

The problem hatches should the Editor and Publisher be the same. For example should the Editor and Publisher both be "University of Chicago Press".

Now, whenever a new Book is saved to the database through the django-admin interface I would like following to happen:

I was thinking of implementing it somehow like this:

class Book:
#...
    def save(self, *args, **kwargs):
        if self.editors.count() <= 0 and self.publisher:
            self.editors = self.publisher #This is not possible
        super(Book, self).save(*args, **kwargs)

The self.editors = self.publisher bit could perhaps be fixed with inheritance, but there are still multiple editors and just one publisher and I dont want publishers and editors to be stored int he same table.

Any thoughts on how to approach this?

Upvotes: 2

Views: 2700

Answers (1)

GwynBleidD
GwynBleidD

Reputation: 20569

With little of re-structuring your models, is possible and will be more flexible than now.

First: don't put publisher and editor to 2 separate models. Make one.

Second: if you can have publisher/editor both person and organization/company (and that will require different model fields), put all common fields into one model and make 2 models that will inherit from that model, containing more specified fields. That will create under the hood one-to-one relation between fields.

Third: create 2 fields in your book model, one ForeignKey named publisher and one ManyToMany named editors. Both relations should point to your base model for publisher/editor.

Sample code:

class PEBase(models.Model): # have no idea how to name it better

    some_common_field = models.Field(...)


class PEPerson(PEBase):

    first_name = models.CharField()
    last_name = models.CharField()


class PEOrganization(PEBase):

    name = models.CharField()
    website = models.URLField()


class Book(models.Model):

    title = models.CharField(unique=True)
    #...
    editors = models.ManyToManyField(PEBase, blank=True, related_name="books_edited")
    publisher = models.ForeignKey(PEBase, blank=True, related_name="books_published")

    def save(self, *args, **kwargs):
        super(Book, self).save(*args, **kwargs)
        if self.editors.count() <= 0 and self.publisher:
            self.editors.add(self.publisher) #This must go after save - ID of book must be already set.

Upvotes: 4

Related Questions