Django 中的抽象模型和外键

Posted

技术标签:

【中文标题】Django 中的抽象模型和外键【英文标题】:Abstract Models and Foreign Keys in Django 【发布时间】:2011-11-23 20:50:28 【问题描述】:

我正在从事一个 django 项目,在该项目中我创建了一组三个抽象模型,稍后我将在各种应用程序中使用它们。我遇到的问题是我想通过 ForeignKey 连接这些模型,但 django 告诉我它不能将外键分配给抽象模型。

我当前的解决方案是在我的其他应用程序中实例化类时分配外键。但是,我现在正在为抽象类(书籍和页面)编写一个管理器,并且需要访问这些外键。我基本上想做的是以无状态的方式获取一本书的字数,因此无需将其存储在页面或书籍的字段中。

模型看起来类似于这样:

class Book(models.Models):
    name = models.CharField(...)
    author = models.CharField(...)
    ...

    class Meta:
        abstract = True

class Page(models.Models):
    book = models.ForeignKey(Book)
    chapter = models.CharField(...)
    ...

    class Meta:
        abstract = True

class Word(models.Models):
    page = models.ForeignKey(Page)
    line = models.IntegerField(...)
    ...

    class Meta:
        abstract = True

请注意,这里的这个模型只是为了举例说明我正在尝试做的事情,因此不需要这个模型(Book-Page-Word)从实现的角度来看是否有意义。

【问题讨论】:

【参考方案1】:

也许您在这里需要的是GenericForeignKey,因为您实际上并不知道您的ForeignKeys 将指向什么型号?这意味着您将失去一些正常关系的“类型安全”保证,但它允许您以更一般的方式指定这些关系。见https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericForeignKey

Django 模型继承是一件很酷的事情,并且可以作为使模型 DRYer 的捷径,但并不总是与我们通常对类的多态想法很好地配合。

【讨论】:

【参考方案2】:

这种方法怎么样?我正在考虑自己使用它来延迟关系定义,直到我继承。

# 这是一个非常做作(但很简单)的例子。

def AbstractBook(AuthorModel):                                                  
    class AbstractBookClass(Model):                                             
        name = CharField(max_length=10)                                         
        author = ForeignKey(AuthorModel)                                        
        class Meta:                                                             
            abstract = True                                                     
    return AbstractBookClass                                                    


class AbstractAuthor(Model):                                                    
    name = CharField(max_length=10)                                             
    class Meta:                                                                 
        abstract = True                                                         


class BadAuthor(AbstractAuthor):                                                
    pass                                                                        

class BadBook(AbstractBook(BadAuthor)):                                         
    pass                                                                        

class GoodAuthor(AbstractAuthor):                                               
    pass                                                                        

class GoodBook(AbstractBook(GoodAuthor)):                                       
    pass                                                                        

【讨论】:

读到这让我很受伤【参考方案3】:

两件事:

1) 如前所述,按照您构建架构的方式,您将需要一个 GenericForeignKey。但是您必须考虑到 Book through Page 与 Word 具有 多对多 关系,而 GenericForeignKey 只是实现 一对多。对于规范化模式,Django 没有任何开箱即用的东西。您将要做的(如果您关心规范化)是自己实现中间体(对于具体模型使用“通过”)。

2) 如果您关心语言处理,考虑到生成的数据库大小和几十本书后的查询时间,使用关系数据库(有或没有 Django 的 ORM)不是一种非常有效的方法。此外,由于抽象模型,您需要查找连接的额外列,它很快就会变得非常不切实际。我认为根据您的查询和视图研究其他方法会更有益,例如仅存储聚合和/或非规范化(在这种情况下甚至研究非关系存储系统)。

【讨论】:

以上是关于Django 中的抽象模型和外键的主要内容,如果未能解决你的问题,请参考以下文章

如何在Django中加入非主键和外键列的查询

一对一和外键关系之间的区别?

sequelize 模型、迁移文件和外键。哪一个是对的?

Django - 来自抽象基类的外键[重复]

使用外键查询 Django 模型并获取登录用户

在自定义主键和外键中定义 Laravel 关系