Обратный внешний ключ в неуправляемой модели не работает

Недавно я столкнулся со следующей проблемой. У меня есть несколько неуправляемых моделей

class A(models.Model):
    # some fields
    class Meta:
        app_label = "app"
        db_table = "table_a"
        managed = False

class B(models.Model):
    # some fields

    a_fk = models.ForeignKey(A, on_delete=models.RESTRICT, related_name="b_objects")

    class Meta:
        app_label = "app"
        db_table = "table_b"
        managed = False

Итак, как вы можете видеть, я добавил related_name="b_objects", который мне нужен для доступа к объектам B из объектов A через django ORM.

Мне нужно получить количество объектов B для каждого объекта A в моем представлении, поэтому я делаю следующее:

class InventoryLocationsCollectionView(ListAPIView):
    queryset = A.objects.prefetch_related("b_objects").annotate(total=Count("b_objects"))

Однако я получаю ошибку о том, что в модели A нет такого поля 'b_objects'.

Я также пытался использовать

queryset = A.objects.raw("my query")

однако это не сработало, поскольку где-то под капотом вызывается .all(), а в сырых наборах запросов нет метода .all().

Кроме того, сложность заключается в том, что мне нужно будет добавить некоторые фильтры и пагинацию, а сырые queryset, похоже, не поддерживают ни того, ни другого.

Есть ли какие-нибудь обходные пути, чтобы заставить обратный внешний ключ работать в неуправляемых моделях?

Обновление:

Что мне помогло, так это использование annotate + RawSQL

queryset = A.objects.annotate(
    total=RawSQL("select count(1) from table_b where a_id = table_b.id", params=[]),
)

Но проблема этого подхода в том, что он довольно медленный. Помимо total, мне нужно будет запросить еще 3 столбца, которые будут содержать количество b_objects, но с дополнительным условием, примерно таким:

london=RawSQL("select count(1) from table_b where a_id = a.id and city = 'London'", params=[]),

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

Может быть, хотя бы есть способ оптимизировать этот подход RawSQL + annotate, чтобы уменьшить количество подзапросов с 4 до 1?

Вернуться на верх