gpt4 book ai didi

python - Django 模型子类化方法

转载 作者:太空狗 更新时间:2023-10-29 21:03:04 24 4
gpt4 key购买 nike

我正在设计一个新的 Django 应用程序,由于有多种可能性,我不确定哪个是最好的,因此我想征求意见,并希望能改进我目前所取得的成果。

This question接近但不完全是。 This one触及有帮助的平面/嵌套主题,但仍未回答问题。在同一主题上还有很多其他人,但没有人告诉我我想知道什么。

背景

模型具有每个独特的属性和一些共享属性,我需要在另一个模型中引用它们,最好使用单个入口点,而不是为每个可能的模型都有一个字段。

我希望能够执行涉及基类的复杂 Django ORM 查询,并在需要时按子类进行过滤。例如 Event.objects.all()返回所有事件。我知道 Django model utils Inheritance Manager并打算在可能的情况下使用它。

此外,我将使用 django admin 来创建和管理对象,因此必须轻松集成。我希望能够直接创建一个新的 SubEvent,而无需首先创建一个 Event 实例。

例子

为了说明,假设我有以下应用程序模型 A .

class Event(models.Model):
commom_field = models.BooleanField()

class Meta:
abstract = True

class SubEventA(Event):
email = models.EmailField(unique=True)

class SubEventB(Event):
title = models.TextField()

class SubEventC(Event):
number = models.IntegerField(default=10)

# and so on

还有一个应用程序 B ,我希望能够引用可以是任何类型的事件,例如:

class OtherModel(models.Model):
event = models.ForeignKey('A.Event')

# This won't work, because `A.Event` is abstract.

可能的解决方案

  1. 使用 GenericForeignKey .

    # B.models.py
    class OtherModel(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    event = GenericForeignKey('content_type', 'object_id')

    我不喜欢的是我会失去 Django ORM 的查询功能,我可能需要做额外的调整才能让它在管理员上工作。不确定,以前从未处理过这个问题

  2. 展平 Event

    我可以将它全部带到基类,并在模型定义之外设置标志或检查,例如:

    class Event(models.Model):
    commom_field = models.BooleanField()
    email = models.EmailField(blank=True)
    title = models.TextField(blank=True)
    number = models.IntegerField(default=10)

    乍一看这似乎是最好的主意,但当然还有其他类型的字段,这迫使我允许其中的大多数字段为空值/空白(例如电子邮件字段),从而失去数据库级别的完整性检查。

  3. 一对一关系

    与其像在1 上那样抽象或在2 上扁平化,还可以为每一个都有一个数据库表,模型看起来像这样:

    class Event(models.Model):
    commom_field = models.BooleanField()

    class SubEventA(models.Model):
    event = models.OneToOneField(Event)
    email = models.EmailField(unique=True)

    class SubEventB(models.Model):
    event = models.OneToOneField(Event)
    title = models.TextField(blank=True)

    class SubEventC(models.Model):
    event = models.OneToOneField(Event)
    number = models.IntegerField(default=10)

    到目前为止,它解决了两个最初的问题,但现在当我进入管理界面时,我必须自定义每个表单以创建基础 Event在保存 SubEvent 之前实例。

问题

  1. 有更好的方法吗?

  2. 我提供的任何选择是否可以在任何方向(ORM 查询、DB 约束、管理界面)进行改进?

最佳答案

我仔细考虑了这两个答案,并根据这些建议提出了一些建议。因此,我要添加我自己的这个答案。

我选择使用 django-polymorphic ,@professorDante 建议的非常好的工具。由于这是一个多表继承,@albar 的回答也有些正确。

tl;博士

django-polymorphic满足 3 个主要要求:

  1. 允许django ORM查询方式
  2. 通过多表继承和每个子类一个表来保持数据库级别的约束
  3. 简单的 django 管理集成

更长的版本

Django-polymorphic 允许我从基类查询所有不同的事件实例,例如:

# assuming the objects where previously created
>>> Event.objects.all()
[<SubEventA object>, <SubEventB object>, <SubEventC object>]

它还有很棒的django admin integration ,允许无缝创建和编辑对象。

使用 django-polymorphic 的模型看起来像:

# A.models.py
from polymorphic import PolymorphicModel

class Event(PolymorphicModel):
commom_field = models.BooleanField()

# no longer abstract

class SubEventA(Event):
email = models.EmailField(unique=True)

class SubEventB(Event):
title = models.TextField()

class SubEventC(Event):
number = models.IntegerField(default=10)



# B.models.py

# it doesnt have to be polymorphic to reference polymorphic models
class OtherModel(models.Model):
event = models.ForeignKey('A.Event')

此外,我可以只引用另一个类的基础模型,我可以直接分配任何子类,例如:

>>> sub_event_b = SubEventB.objects.create(title='what a lovely day')
>>> other_model = OtherModel()
>>> other_model.event = sub_event_b

关于python - Django 模型子类化方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33105782/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com