简体   繁体   English

Django抽象与非抽象模型继承

[英]Django absract vs non-abstract model inheritance

Consider these two model classes Book and Article : 考虑这两个模型类BookArticle

class Book(models.Model):
    title = models.CharField(max_length=100)


class Article(models.Model):
    title = models.CharField(max_length=100)

Imagine this scenario: a book can have many annotations but an annotation can refer to only one book. 想象一下这种情况:一本书可以有很多注释,但是注释只能引用一本书。 Same thing for the article. 文章也是一样。 I have developed two solutions: 我已经开发了两种解决方案:

Non-abstract solution 非抽象解决方案

class Annotation(models.Model):
    body = models.TextField()
    article = models.ForeignKey(Article, blank=True)
    book = models.ForeignKey(Book, blank=True)

    class Meta:
        default_related_name = 'annotations'

Pros 优点

  • Code is DRY 代码是DRY
  • One can access the annotations with book.annotations or article.annotations 可以使用book.annotationsarticle.annotations访问注释

Cons 缺点

  • Waste database memory (one of the two fields article , book must be none) 浪费数据库内存(两个字段articlebook必须为none)

Abstract classes solution 抽象类解决方案

class Annotation(models.Model):
    body = models.TextField()

    class Meta:
        abstract = True


class BookAnnotation(Annotation):
    book = models.ForeignKey(Book, blank=True)

    class Meta:
        default_related_name = 'book_annotations'


class ArticleAnnotation(Annotation):
    article = models.ForeignKey(Article, blank=True)

    class Meta:
        default_related_name = 'article_annotations'

Pros 优点

  • Clear separation for book and article annotations 明确区分书籍和文章注释
  • No memory waste 没有内存浪费

Cons 缺点

  • Does not quite match the concept of annotation (the object type should be the same) 与注释的概念不太匹配(对象类型应该相同)
  • One can access the annotations with book.book_annotations or article.article_annotations (kind of ugly isn't it?). 可以使用book.book_annotationsarticle.article_annotations访问注释(不是很丑吗?)。 I can not use annotations as related name because Django prohibit that, it says reverse query name for BookAnnotation clashes with field name ArticleAnnotation . 我不能将annotations用作相关名称,因为Django禁止这样做,它说reverse query name for BookAnnotation clashes with field name ArticleAnnotation

Which is the best approach to deal with such situation? 处理这种情况的最佳方法是哪种?

You might consider generic relations here. 您可以在这里考虑一般关系

class Annotation(models.Model):
    body = models.TextField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    annotated_object = GenericForeignKey('content_type', 'object_id')

class Book(models.Model):
    ...
    annotations = GenericRelation('Annotation')

class Article(models.Model):
    ...
    annotations = GenericRelation('Annotation')

now you can set annotation.annotated_object to any book or article instance, and in reverse do obj.annotations from both book and article objects. 现在,您可以将annotation.annotated_object obj.annotations设置为任何书籍或文章实例,相反,可以同时对书籍和文章对象进行obj.annotations

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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