Повторяющиеся записи выбираются в отфильтрованном квесте - PullRequest
1 голос
/ 29 марта 2020

У меня есть немного сложная комбинация фильтра | &, подобного этому.

objs = objs.annotate(num_line=Count("lns")).\
    filter(Q(lns__id__in=lnIds) | (Q(sts__id__in=oIds) 
        & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))))

Это похоже на работу, но результаты иногда дублируются (с таким же идентификатором).

   id
    1
    2
    3
    3
    4
    5

Я думал, что фильтр вернет уникальный идентификатор, хотя, я не прав ??

Или возможно опустить дублированные строки ??

class Obj(models.Model):
    created_at = models.DateTimeField(null=True)
    lns = models.ManyToManyField(Ln)
    sts = models.ManyToManyField(St)
    is = models.ManyToManyField(Is)
    pub_date = models.DateTimeField('date published')

1 Ответ

1 голос
/ 29 марта 2020

Нет, если вы отфильтруете отношения «один ко многим» или «многие ко многим», это создаст JOIN со связанной таблицей, и если несколько объектов совпадут, то это приведет к получению одного и того же значения несколько раз.

Вы можете использовать .distinct(..) (Django -do c) для фильтрации дублирующихся строк.

objs = objs.filter(
    Q(lns__id__in=lnIds) |
    (Q(sts__id__in=oIds) & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))
)<b>.distinct()</b>

Еще более проблематично c в том, что если вы добавите аннотацию, то это может привести к тому, что счетчик также будет считать дубликаты. Вы можете добавить distinct=True [Django -doc] к выражению Count(..), чтобы предотвратить это:

objs = objs.annotate(
    num_line=Count('lns'<b>, distinct=True</b>)
).filter(
    Q(lns__id__in=lnIds) |
    (Q(sts__id__in=oIds) & (Q(lns__id__in=lnIds) | Q(num_ln__lte=0))
).distinct()
...