Фильтр Django по атрибуту с двумя значениями, предпочитая результат одного

Это довольно странный вопрос, поэтому заранее извините. У меня есть модель в Django Rest, которая выглядит так:

class BaseModel(models.Model):
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)

   class Meta:
        abstract = True

class Foo(BaseModel):
    barId = models.ForeignKey(Bar, unique=False)
    fizzId = models.ForeignKey(Fizz, unique=False)
    buzzId = models.IntegerField(unique=False)
    value = models.TextField()

И у меня есть ViewSet, который должен вернуть список всех Foo, которые имеют заданный {request_barId, request_buzzId, lastUpdateDate}. Это довольно просто,

foobar = Foo.objects.filter(
buzzId=request_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId)

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

base_foobar = Foo.objects.filter(
buzzId=base_buzzId,
modified_date__gt=request_lastUpdateDate,
barId=request_barId).exclude(
        fizzId__in=[o.fizzId for o in foobar])
result = foobar | base_foobar

И это только кажется действительно извращенным. Есть ли способ убрать это?

РЕДАКТИРОВАТЬ: для пояснения, скажем, что список для кортежа { 1, 0, '01-01-1970' } представляет базовый набор (buzzId: 0) и возвращает список объектов, содержащих fizzIds { 1, 2, 3, 10 }. Предположим, что кортеж { 1, 1, '01-01-1970' } представляет запрос некоторого buzzId на полный набор строк. Если мы скажем, что наш buzzId из 1 (назовите его augment) имеет совпадающие значения Foos с fizzIds { 2, 10, 15, 20 }, то наш набор результатов должен выглядеть следующим образом

{ (base) 1, (augment) 2, (base) 3, (augment) 10, (augment) 15, (augment) 20 }

Это проясняет?

1 ответ

Решение

Вы могли бы использовать Q объединить в одно утверждение:

result = (Foo.objects
    .filter(
        Q(
            modified_date__gt=request_lastUpdateDate,
            barId=request_barId
        ) 
        &
        (
            Q(buzzId=request_buzzId) 
            |
            (
                Q(buzzId=base_buzzId)
                & 
                ~Q(fizzId__in=[o.fizzId for o in foobar])
            )
        )
    )
    .order_by( '-buzzId' if request_buzzId < base_buzzId else 'buzzId')
    )[0] # fetch first result only

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

Другие вопросы по тегам