Обратный внешний ключ в неуправляемой модели не работает
Недавно я столкнулся со следующей проблемой. У меня есть несколько неуправляемых моделей
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?