Возвращение текущего статуса проекта (то есть самой последней даты в отношениях Django ManyToMany) - PullRequest
1 голос
/ 25 октября 2011

Описание схемы

Статус проекта может со временем меняться.Чтобы отслеживать состояние с течением времени, я создал отношение «многие ко многим» между моделью Project и моделью ProjectStatusType с помощью промежуточной таблицы ProjectStatus.

Хотя это позволяет отслеживать состояние проекта с течением времени, это увеличивает сложность схемы, так что получение текущего статуса проекта или получение всех открытых проектов становится более трудным.

enter image description here

Вариант использования

Я хочу иметь возможность вернуть все проекты, находящиеся в заданном состоянии, например, все проекты open.Например, когда пользователи переходят на http://www.example.com/projects,, я бы хотел, чтобы по умолчанию в таблице отображались только проекты open.

Вопросы

  1. Должен ли яденормализовать схему и добавить поле current_status в модель Project?
  2. Если я не должен денормализовать, какую стратегию мне следует использовать для получения текущего статуса для каждого проекта?Должен ли я создать свойство в модели Project, которое получает текущий статус?

Ответы [ 2 ]

1 голос
/ 25 октября 2011

Если вам не нужно искать по нему, я бы создал свойство на модели проекта. Вы можете использовать функцию Max для aggregate, чтобы получить запись с самой новой датой.

from django.db.models import Max

class Project(models.Model):
    [...]

    @property
    def status_date(self):
        return self.projectstatus_set.aggregate(newest=Max('status_date'))['newest']

Эта стратегия задокументирована здесь .

Если вам нужно выполнить поиск, то вам следует денормализовать и добавить поле в Project. Вы можете сохранить его текущим, используя сигналы. Вы бы хотели добавить слушателя post_save в ваше поле ProjectStatus, которое установило бы дату его проекта в статус '.

from django.db.signals import post_save

def update_status_date(sender, instance=None, **kwargs):
    project = instance.project
    project.status_date = max(project.status_date, instance.status_date)
    project.save()
post_save.connect(update_status_date, sender=ProjectStatus)

Подробнее о сигналах можно прочитать здесь .

======

РЕДАКТИРОВАТЬ: С момента написания моего первоначального ответа, ОП несколько прояснил свой вопрос, и его разъяснение изменяет пример кода для обеих моих стратегий, хотя не их базовую конструкцию. Я хочу оставить первоначальный ответ тем, кому, возможно, нужны более родственные вопросы, на которые, как мне казалось, я отвечал в то время.

В моем первом примере он на самом деле не хочет самой новой даты status_date, а скорее самого нового типа статуса проекта. Это существенно изменило бы свойство; вам вообще не нужно использовать SQL-конструкцию MAX(); Вы просто хотите, чтобы первая запись была прикреплена к этому объекту, когда упорядочено по убыванию даты:

class Project(models.Model):
    [...]

    @property
    def project_status(self):
        return self.status.order_by('-status_date')[0]

Варианты использования вокруг этого все те же. Если вы всегда сначала получаете проект, а затем хотите узнать его текущее состояние, то это правильный путь. Если вам нужно индексировать проектов по статусу, то вам нужно денормализовать. Лучше всего это сделать с помощью сигналов, но вместо сохранения даты, как я делал в моем примере выше, вы, вероятно, захотите сохранить описание. Принцип остается тем же, хотя.

0 голосов
/ 25 октября 2011

По вашему описанию, я предполагаю, что вы на самом деле используете ProjectStatus в качестве through для вашего ManyToManyField, и что вы уже храните дополнительные данные об отношениях с этой моделью.Если один из элементов дополнительных данных еще не является датой и временем, когда был установлен этот конкретный статус, я бы добавил это в вашу модель.первый ProjectStatus возвращенный всегда будет самым последним (текущим).

...