【问题标题】:Is there a sane way to simulate virtual inheritance in Django models?有没有一种健全的方法来模拟 Django 模型中的虚拟继承?
【发布时间】:2012-02-18 19:07:55
【问题描述】:

我想记录用户的操作。在大多数 OO 语言中,我会通过 LoggedAction 类来实现这一点,它有几个子类,如 LoginActionLogoutAction。然后我可以遍历LoggedActions 的列表,并通过虚拟继承获得特定的子行为。但是,这不适用于 Django 模型。

例如models.py:

class LoggedAction(models.Model):
    user = models.ForeignKey(User)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return "%s: %s %s" % (unicode(self.timestamp), unicode(self.user), unicode(self.action()))

    def action(self):
        return ""

class LoginAction(LoggedAction):
    def action(self):
        return "logged in"

class LogoutAction(LoggedAction):
    def action(self):
        return "logged out"

然后我想做[unicode(l) for l in LoggedAction.objects.all()] 并获取u'2012-02-18 18:47:09.105840: knatten logged in' 之类的消息列表。

正如预期的那样,这不起作用,因为我从all() 得到的是LoggedAction 对象的列表,该对象具有loginaction 成员或logoutaction 成员。 (输出是u'2012-02-18 18:47:09.105840: knatten 之类的消息列表,没有提及操作。)

有没有一种理智的方法来获得我所追求的行为,还是我试图在这里应用错误的范例? (我想我是,我应该只是在LoggedAction 中作为成员进行具体操作)

【问题讨论】:

  • 意识到,正如您在此处展示的那样,它将在数据库中实现为三个表,LoginAction 和 LogoutAction 连接在一个公共表上,并且可以实例化 LoggedAction 对象。您可能希望将 LoggedAction 抽象化。
  • @ChrisMorgan 如果我将LoggedAction 抽象化,我将无法遍历它们,对吗?所以特别是LoggedAction.objects.all() 是不可能的?
  • 不确定;事实上,我从来没有理由用子类迭代模型。

标签: python django oop inheritance virtual-inheritance


【解决方案1】:

是的,这可能是错误的范例。对象关系映射器 (ORM) 很容易误导 - 数据库表并没有真正将所有对象映射到对象,这种差异被称为 object-relational impedance mismatch

您真正需要的是使action 成为一个字段。该字段可以采用choices 参数,该参数表示该字段的可能值 - 即登录或注销:

class LoggedAction(models.Model):
    ACTIONS = (
       ('I', 'logged in'),
       ('O', 'logged out')
    )
    user = models.ForeignKey(User)
    timestamp = models.DateTimeField(auto_now_add=True)
    action = models.CharField(max_length=1, choices=ACTIONS)

    def __unicode__(self):
        return u"%s: %s %s" % (self.timestamp, self.user, self.get_action_display())

请注意,我使用任意单字符串来表示动作,并使用get_action_display() 魔术方法来获取完整描述。

【讨论】:

  • 是的,期望能够在关系数据库之上实现完整的 OO 可能有点乐观。我希望能够在子类中存储一些额外的信息,但它们可能都是TextField。所以我想我可以采用你的解决方案,在 LoggedAction 类中使用 TextField
【解决方案2】:

查看来自 django-model-utils 的 InheritanceManager。它允许您获取具体的子类。

【讨论】:

    猜你喜欢
    • 2015-09-09
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 2020-02-15
    • 1970-01-01
    • 2018-03-31
    相关资源
    最近更新 更多