Django Model Field for Abstract Base Class

| 我已经在堆栈溢出附近搜索了这个(可能很简单)问题的答案,但是我看到的大多数解决方案似乎都过于复杂且难以理解。 我有一个模型“ Post”,它是一个抽象的基类。模型“公告”和“事件”继承自Post。 目前,我在其他模型中保留了事件和公告的相关列表。例如,我在另一个模型中有\“ removed_events \”和\“ removed_announcements \”字段。 但是,在我的项目中,\“ removed_events \”和\“ removed_announcements \”的处理方式完全相同。无需在“已删除的事件”和“已删除的公告”之间进行区分。换句话说,跟踪“已删除的帖子”的字段就足够了。 我不知道如何(或者也许不能)创建一个字段“ removed_posts”,因为Post是抽象的。但是,现在我感觉我在代码中重复我自己(并且必须做很多杂乱的检查来弄清楚我正在查看的帖子是事件还是公告,然后将其添加到相应的已删除字段)。 这里最好的选择是什么?我可以使Posts成为非抽象对象,但绝对不要创建Post对象本身,并且我认为我不能在非Abstract对象上强制执行此操作。 我对数据库的理解很薄弱,但是我的印象是,由于联接的原因,使Post非抽象将使数据库复杂化。这有什么大不了的吗? 最后,在其他模型中的其他字段中,我想将等于event_list和announcement_list的内容压缩为post_list,但是这些字段确实需要消除歧义。我可以根据帖子类型过滤post_list,但是对filter()的调用要比能够分别直接访问事件列表和公告列表要慢,不是吗?有什么建议吗? 非常感谢您阅读此书。     
已邀请:
Django中有两种模型子类-抽象基类;和多表继承。 抽象基类自己从未使用过,并且没有数据库表或任何形式的标识。通过将代码中而不是数据库中的公共字段集进行分组,它们只是缩短代码的一种方法。 例如:
class Address(models.Model):
    street = ...
    city = ...

    class Meta:
        abstract = True


class Employee(Address):
    name = ...

class Employer(Address):
    employees = ...
    company_name = ...
这是一个人为的示例,但是正如您所看到的,
Employee
不是2ѭ,也不是3ѭ。它们都只包含与地址有关的字段。在此示例中只有两个表。
Employee
Employer
-它们都包含地址的所有字段。在数据库级别,不能将雇主地址与雇员地址进行比较-地址没有自己的密钥。 现在,有了多表继承(从address删除abstract = True),Address本身就拥有一个表。这将产生3个不同的表;
Address
Employer
Employee
。雇主和雇员都将具有唯一的外键(OneToOneField)回到地址。 现在,您可以引用地址,而不必担心地址的类型。
for address in Address.objects.all():
    try:
        print address.employer
    except Employer.DoesNotExist: # must have been an employee
        print address.employee
每个地址都有自己的主键,这意味着它可以单独保存在第四张表中:
class FakeAddresses(models.Model):
    address = models.ForeignKey(Address)
    note = ...
如果您需要使用
Post
类型的对象而不必担心它是哪种Post类型,那么多表继承就是您的追求。如果从子类访问任何Post字段,则将产生连接的开销;但开销却很小。这是一个独特的索引联接,它应该非常快。 只要确保,如果您需要访问
Post
,就可以在查询集上使用
select_related
Events.objects.select_related(depth=1)
这样可以避免进行其他查询来获取父数据,但是会导致联接的发生。因此,仅在需要发布时才使用select related。 最后两点笔记;如果发布既可以是公告也可以是事件,那么您需要做传统的事情,并通过ForeignKey链接到Post。在这种情况下,没有子类将起作用。 最后一件事是,如果联接对父级和子级之间的性能至关重要,则应使用抽象继承;并使用“通用关系”来引用对性能要求不高的表中的抽象帖子。 通用关系实质上是这样存储数据的:
class GenericRelation(models.Model):
    model = ...
    model_key = ...


DeletedPosts(models.Model):
    post = models.ForeignKey(GenericRelation)
要在SQL中进行连接,要复杂得多(django可以帮助您完成此工作),但与简单的OneToOne连接相比,其性能也要差一些。如果OneToOne联接严重损害了应用程序的性能(这不太可能),则只需要沿这条路线走。     
通用关系和外键是您成功之路的朋友。定义一个中间模型,其中一侧是通用的,然后另一侧将获得相关的多态模型列表。它比标准的m2m连接模型稍微复杂一点,因为泛型端有两列,一列是ContentType(实际上是FK),另一列是实际链接的模型实例的PK。您也可以限制使用标准FK参数链接的模型。 您很快就会习惯它。 (现在我得到了一个可以用来书写的实际键盘,下面是示例:)
class Post(models.Model):
    class Meta: abstract = True
    CONCRETE_CLASSES = (\'announcement\', \'event\',)
    removed_from = generic.GenericRelation(\'OwnerRemovedPost\',
        content_type_field=\'content_type\',
        object_id_field=\'post_id\',
    )

class Announcement(Post): pass

class Event(Post): pass

class Owner(models.Model):

    # non-polymorphic m2m
    added_events = models.ManyToManyField(Event, null=True)

    # polymorphic m2m-like property
    def removed_posts(self):
        # can\'t use ManyToManyField with through.
        # can\'t return a QuerySet b/c it would be a union.
        return [i.post for i in self.removed_post_items.all()]

    def removed_events(self):
        # using Post\'s GenericRelation
        return Event.objects.filter(removed_from__owner=self)


class OwnerRemovedPost(models.Model):
    content_type = models.ForeignKey(ContentType,
        limit_choices_to={\'name__in\': Post.CONCRETE_CLASSES},
    )
    post_id = models.PositiveIntegerField()
    post = generic.GenericForeignKey(\'content_type\', \'post_id\')
    owner = models.ForeignKey(Owner, related_name=\'removed_post_items\')

    class Meta:
        unique_together = ((\'content_type\', \'post_id\'),)  # to fake FK constraint
您无法像经典的多对多过滤器那样过滤相关的集合,但是使用ѭ17the中的适当方法,并且巧妙地使用具体类的管理器,您可以到达所需的任何地方。     

要回复问题请先登录注册