2012-02-18 81 views
3

我想记录用户所做的动作。在大多数OO语言中,我将通过LoggedAction类实现此功能,其中有几个子类,如LoginActionLogoutAction。然后我可以遍历一个列表LoggedAction s,并通过虚拟继承来获取特定的子行为。但是,这不适用于使用Django模型。有没有在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()得到的是具有或者一个loginaction成员或成员logoutaction对象LoggedAction的列表。 (输出是一样u'2012-02-18 18:47:09.105840: knatten消息列表,没有提到的动作。)

是否有一个健全的方式拿到后,我的行为,还是我想在这里应用错误的范例? (我想我是,我应该只是作为LoggedAction成员的具体行动)

+0

认识到,正如您在此处显示的那样,它将在数据库中以三个表的形式实现,其中LoginAction和LogoutAction加入到公共表中,并且可以实例化LoggedAction对象。您可能想要使LoggedAction抽象。 – 2012-02-18 22:11:53

+0

@ChrisMorgan如果我使'LoggedAction'抽象,我无法迭代它们,对吧?所以特别是'LoggedAction.objects.all()'将不可能? – knatten 2012-02-18 22:15:06

+0

不确定;事实上,我从来没有理由用一个子类迭代模型。 – 2012-02-18 22:20:32

回答

2

是的,这可能是错误的范例。被对象关系映射器(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()魔术方法来获得完整的描述。

+0

是的,期望能够在关系数据库上打击完整的OO可能有点乐观。 我希望能够在子类中存储一些额外的信息,但它们可能都是'TextField'。所以我想我可以使用你的解决方案,在LoggedAction类中使用'TextField'。 – knatten 2012-02-19 11:37:36

1

看看来自django-model-utils的InheritanceManager。它可以让你获得具体的子类。