В приведенном ниже примере у продукта есть много авторов через участника, а contributor.role_code определяет точный вид вклада, внесенного в продукт. Возможно ли с помощью Django ORM фильтровать участников, на которые ссылается метод order_by () ниже? Например. Я хочу заказывать продукты только участников, таких как contributor.role_code in ['A01', 'B01'].

Product.objects.filter(
    product_type__name=choices.PRODUCT_BOOK
).order_by(
    'contributor__writer__last_name'    # filter which contributors it uses?
)
0
ryanmrubin 27 Фев 2015 в 23:41

2 ответа

Лучший ответ

Вы можете сделать это с помощью подзапроса аннотации:

  1. Определите подзапрос, который представляет то, что мы хотим упорядочить
  2. Аннотируйте исходный QuerySet с помощью подзапроса
  3. Заказ по аннотации.
contributors_for_ordering = Contributor.objects.filter( # 1
    product=OuterRef('pk'),
    role_code__in=['A01', 'B01'],
).values('writer__last_name')

queryset = Product.objects.filter(
    product_type__name=choices.PRODUCT_BOOK
).annotate( # 2
    writer_last_name=Subquery(contributors_for_ordering[:1])  # Slice [:1] to ensure a single result
).order_by( # 3
    'writer_last_name'
)

Однако обратите внимание, что здесь есть потенциальная причуда. Если у продукта есть участники с обоими «A01» и «B01», мы не контролировали, какой из них будет использоваться для заказа - мы получим то, что база данных вернет первым. Вы можете добавить предложение order_by к contributors_for_ordering, чтобы справиться с этим.

1
Kyle 14 Апр 2020 в 23:22

Чтобы отфильтровать определенные значения, сначала составьте список допустимых значений:

accepted_values = ['A01', 'B01']

Затем отфильтруйте значения в этом списке:

Product.objects.filter(
        product_type__name=choices.PRODUCT_BOOK
    ).filter(
        contributor__role_code__in=accepted_values
    ).order_by(
        'contributor__writer__last_name'
    )
0
dylrei 27 Фев 2015 в 23:21