Запрос элементов с использованием фильтра для самой последней записи в связанной таблице - PullRequest
0 голосов
/ 29 марта 2011

Здравствуйте, у меня возникли проблемы с запросами.У меня есть список предметов.Любой элемент может иметь статус, установленный для него (In, Out, Collected, Destroyed и т. Д.).Вот мои взгляды.

def client_summary(request, client_id):
    client = None
    items = None
try:
    client = models.Client.objects.get(pk = client_id)
    items = client.storageitem_set.all()
    total_items = items.count()
    except:
        return HttpResponse(reverse(return_clients))
    return render_to_response('client_summary.html', {'items':items, 'total_items':total_items, 'client':client}, context_instance = RequestContext(request))

Если у меня есть в моем шаблоне

{%for item in items%}
        {{item.itemstatushistory_set.latest}}
{%endfor%}

Это будет отображать все последние статус.Теперь я хочу только распечатать все предметы, которые имеют только статус Уничтожено.По какой-то причине я не могу этого сделать.

Вот еще некоторая информация из моих моделей.

class StorageItem(models.Model):
    type = models.ForeignKey(StorageObject)
    client = models.ForeignKey(Client)
    company_id = models.PositiveIntegerField(unique = True, blank = True, null = True)
    content = models.TextField(blank = True)
    alternative_id = models.CharField(verbose_name = 'Client no.', max_length = 60, blank = True)
    title = models.CharField(max_length = 100)
    format = models.ForeignKey(Format, blank = True, null = True)
    location = models.CharField(max_length = 20, blank = True)
    item_class = models.TextField(blank = True)

    def __unicode__(self):
        return self.title

class Status(models.Model):
    description = models.CharField(max_length = 60)
    notes = models.TextField(blank = True)
    def __unicode__(self):
        return self.description

    class Meta:
        verbose_name_plural = 'Status'
        get_latest_by = 'date'
        ordering = ['date']

class ItemStatusHistory(models.Model):
    date = models.DateTimeField(auto_now = True)
    contact = models.ForeignKey(Contact)
    item = models.ForeignKey(StorageItem)
    status = models.ForeignKey(Status)
    user = models.ForeignKey(User)

    def __unicode__(self):
        return str(self.status

EDIT : Есть еще некоторые проблемы, потому что отношение между предметом может иметь много состояний.Но я хочу перечислить только самый последний статус только для уничтоженных предметов.

Пример: Предположим, есть 3 предмета и они имеют наборы item1 = [in, out, destroyed], item2 = [destroyed, in], item3 = [destroyed, collected, destroyed], item4 = [in] где [1st status, 2nd status, 3rd status, etc].Я только хочу отобразить последний статус этого элемента.

Майк и Кригар получат результат, подобный [item1, item2, item3, item3].Поскольку Юджи использовал отличную функцию, он получит [item1, item2, item3].

Ответ, который мне нужно получить в конце, должен быть [item1, item3].

Ответы [ 2 ]

0 голосов
/ 29 марта 2011

решение Кригара будет работать. Также есть этот, который ищет по статусу id вместо сопоставления текста на description:

destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status=destroyedStatus)

Это предполагает, что описания уникальны, но у вас нет такого ограничения в вашей модели. Я понятия не имею, какая реализация быстрее.

РЕДАКТИРОВАТЬ: Кстати, если у вас есть какая-то сумасшедшая система, в которой у вас есть несколько Статусов с описанием «уничтожен», и вы хотите вместо этого запросить по состоянию id с из description, вы бы просто сделали:

destroyedStatusIDs = Status.objects.filter(description="destroyed").values_list("id", flat=True)
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status__in=destroyedStatusIDs)

Кстати, считается хорошей практикой устанавливать related_name в ваших ForeignKey, OneToOneField и ManyToManyField отношениях, обычно во множественном числе. Таким образом, ваш класс истории становится:

class ItemStatusHistory(models.Model):
    date = models.DateTimeField(auto_now=True)
    contact = models.ForeignKey(Contact, related_name="history")
    item = models.ForeignKey(StorageItem, related_name="history")
    status = models.ForeignKey(Status, related_name="history")
    user = models.ForeignKey(User, related_name="history")

, который изменил бы мой первый пример на:

destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.filter(client=client, 
    history__status=destroyedStatus)

РЕДАКТИРОВАТЬ 2: Ах, так что вы хотите рассмотреть только текущий (т.е. последний) статус. Именно здесь приходят агрегация и F объектов . По сути, идея состоит в том, чтобы база данных создала «поддельный столбец» в таблице, в которой date последней ( т. е. максимальный date) Статус, затем требуется сопоставить дату и статус:

from django.db.models import F, Max

destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.annotate(
    last_change_date=Max("itemstatushistory__date")).filter(client=client, 
    itemstatushistory__status=destroyedStatus, 
    itemstatushistory__date=F("last_change_date"))

Я не проверял это, это первый раз, когда я пробовал это, и может быть лучший способ, поэтому комментарии приветствуются.

0 голосов
/ 29 марта 2011

Если вы хотите, чтобы набор запросов принадлежал клиенту и был уничтожен:

clients_destroyed_items = StorageItem.objects.filter(client=client, 
    itemstatushistory__status__description='destroyed')

Поиск, который охватывает отношения¶

Django предлагает мощный и интуитивно понятный способ"следить" за отношениями в поисках, автоматически заботясь о соединениях SQL для вас, за кулисами.Чтобы охватить отношение, просто используйте имя поля связанных полей в разных моделях, разделенных двойным подчеркиванием, пока не доберетесь до нужного поля.

В этом примере извлекаются все объекты Entry с блогом с именем «Beatles».Блог ':

Entry.objects.filter (blog_ name _exact =' Блог Beatles ')

Этот охват может быть настолько глубоким, насколько вы хотите.

Он также работает в обратном направлении.Чтобы сослаться на «обратную» связь, просто используйте строчное название модели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...