简体   繁体   中英

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:

  • If one or more Editors are given, save it as in the model above.
  • If no Editors are given but a Publisher is given then make editors point to the same key publisher is pointing to
  • If none of both are given leave both blank

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM