Есть ли разумный способ симулировать виртуальное наследование в моделях Django? - PullRequest
3 голосов
/ 18 февраля 2012

Я хочу регистрировать действия пользователей. В большинстве ОО-языков я реализую это через класс LoggedAction, имеющий несколько дочерних классов, таких как LoginAction и LogoutAction. Затем я мог бы перебрать список LoggedAction s и получить конкретное поведение ребенка через виртуальное наследование. Однако это не работает при использовании моделей 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)

Ответы [ 2 ]

2 голосов
/ 19 февраля 2012

Да, это, вероятно, неправильная парадигма. Объектно-реляционный маппер (ORM) может легко ввести в заблуждение - таблицы базы данных не очень хорошо отображают объекты, и это различие известно как несоответствие объектно-реляционного импеданса .

Что вам действительно нужно, так это сделать 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() для получения полного описания.

1 голос
/ 19 февраля 2012

Взгляните на InheritanceManager из django-model-utils.Позволяет получить конкретные подклассы.

...