Как сделать ЛЕВЫЙ ВНЕШНИЙ СОВМЕСТНЫЙ QuerySet в Django - многие к одному - PullRequest
1 голос
/ 05 апреля 2019

У меня есть две модели: изображение (имя файла, uploaded_at) и аннотация (автор, качество, ... fk изображение).

Изображение может иметь несколько аннотаций, а аннотации принадлежат одному изображению.

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

Все хорошо, пока здесь, но я хотел бы отобразить также изображения, которые не были созданы аннотации (левое внешнее объединение), и не уверен, как я могу продолжить делать это?

Чтобы уточнить, я пытаюсь получить данные, чтобы я мог построить таблицу следующим образом:

Image name, Image date, Annotation author, Annotation Quality
image 1   , 2019      , john             , high
image 2   , 2019      , doe              , high
image 3   , 2019      , null             , null
image 4   , 2014      , doe              , high

Может быть, я использую неправильный подход, я использую Аннотацию в качестве основной модели, но тогда у меня нет возможности отображать изображения, которые не имеют Аннотации, что имеет смысл, поскольку есть Нет Аннотация. Вот что я делаю:

Annotation.objects.select_related('image').filter(Q(image__isnull=True)
 | Q(other condition))

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

Image.objects.prefetch_related('annotations').filter(Q(annotations__isnull=True) | Q(other condition))

Prefetch_related, похоже, не имеет никакого значения для запроса, плюс я хотел бы, чтобы данные аннотации располагались в одной и той же строке (т. Е. Строка 1: изображение 1, аннотация 1; строка 2: изображение 1, аннотации 2 и т. д.) вместо создания изображения. annotation_set ... поскольку это не соответствует моим потребностям.

Любой совет будет очень признателен.

Спасибо!

1 Ответ

2 голосов
/ 05 апреля 2019

Если вам нужно внешнее соединение, это должно быть левое соединение, как вы правильно предположили. Поэтому вам придется начинать с модели Image. Чтобы получить плоское представление, а не вложенные Annotation объекты, используйте values ​​() , который возвращает набор запросов словарей (а не объектов модели):

queryset_of_dictionaries = (Image.objects
    .filter(Q(annotations__isnull=True) | Q(other condition))
    .values('name', 'date', 'annotations__author', 'annotations__quality',
            # etc. – you have to enumerate all fields you need
    )
    # you'll probably want the rows in a particular order
    .order_by(
        # a field list like in values()
    )
)

# accessing the rows
for dic in queryset_of_dictionaries:
    print(f'Image name: {dic["name"]}, quality: {dic["annotations__quality"]}')
...