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

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"

然后我想做models.py并得到一个类似[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中的一个成员有具体的行动)

最佳答案

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

10-01 19:38