简体   繁体   中英

How to create a many to one relationship in Django?

as the question states, how do I do create a many-to-one relationship in django models?

Basically, I have two models: Article and Comic, I want to have one Comment model which will have a relationship with both Article and Comic, but not both. So if a Comment object has a relationship with an Article object, then it wont have a relationship with a Comic object.

I am currently doing it the following way, which does not work:

class Article(models.Model):
    #other fields
class Comic(models.Model):
    #other fields
class Comment(models.Model):
    article = models.ForeignKey(Article)
    comic = models.ForeignKey(Comic)

I would really appreciate some help.

This is tricky. I think there are a couple ways you could model this.

Using your current way you could enforce your uniqueness constraint in the application.

class Comment(models.Model):
    article = models.ForeignKey(Article)
    comic = models.ForeignKey(Comic)

    def save(self, *args, **kwargs):
        # assert that there is either comic OR article but not both
        super(Comment, self).save(*args, **kwargs)

with this way, what happens if you add another model that you want Comment to reference?? You will have to manually add the conditional for the new type in your save method and perform a migration.

Django provides GenericForeignKey field that would allow you to reference any model from Comment . https://docs.djangoproject.com/en/1.8/ref/contrib/contenttypes/#generic-relations

This would allow you to create a generic reference from Comment to either Article or Comic, and since it is only one field, would by default be mutually exclusive. I find querying and using GenericeForeignKey s awkward; but they are still an option, that might work fine for your use case.


Another powerful option, (my favorite) could be to create a polymorphic model, which would also be mutually exclusive.

Each Comment could reference a generic Piece of Content , using model inheritance. (I did not test the following, so it will probably not work as copied/pasted)

class Content(models.Model):
  objects = InheritanceManager()
  # shared content fields could be stored in this model

class Article(Content):
  # article specific fields

class Comic(Content):
  # comic specific fields

class Comment(models.Model):
  content = models.OneToOneField(Content)

This is a powerful way to model the relationship of Comment to any Content . This DOES add additional query overhead, and should warrant an audit for your use case.

InheritanceManager is a utility provided by django-model-utils package, and is pretty lightweight. I have used in in production environment and it is performant, as long as you understand the additional query overheard involved with modeling your data using it. https://django-model-utils.readthedocs.org/en/latest/managers.html#inheritancemanager

The query overhead is explained in the documentation.

If you think you will add additional Content subclasses in the future this could be a scalable way to model your relationship, and provides more flexibility in filtering then GenericForeignKey s.

Well, you can add another field to you Comment model. Like

class Comment(models.Model):
    article = models.ForeignKey(Article, null = True)
    comic = models.ForeignKey(Comic, null = True)
    assigned = models.BooleanField(initial=False)

Once a comment object is created, put either article or comic to point at another object and make assigned = True.

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