Django: select_related с наследованием нескольких таблиц - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть следующая структура модели:

class A(models.Model):
    prop_a = models.CharField(max_length=255)

class B(A):
    prop_b = models.CharField(max_length=255)

class C(A):
    prop_c = models.CharField(max_length=255)

class D(models.Model):
    fk = models.ForeignKey('A')

Итак, по сути, у меня есть модель (D), которая имеет внешний ключ к «абстрактной» модели (A), которая находится в подклассахB и C.

Теперь, когда я запускаю D.objects.all().select_related(), запрашиваются только свойства A.Я предполагаю, что это потому, что во время запроса Django не знает, какой дочерний класс является экземпляром fk (и я не знаю в моей текущей структуре).

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

Я также пробовал prefetch_related и пытался использовать InheritanceManager из django-model-utils , оба безрезультатно.

Редактировать: Чтобы уточнить,Я ищу способ перебирать объекты D, получая доступ к конкретным значениям fk (которые являются либо B, либо C объектами), одновременно обращаясь к базе данных только один раз.

ЗапускD.objects.all().select_related() создает запрос

'SELECT "mapping_d"."id", "mapping_d"."fk_id", "mapping_a"."id", "mapping_a"."prop_a" FROM "mapping_d" INNER JOIN "mapping_a" ON ("mapping_d"."fk_id" = "mapping_a"."id")'

Допустим, одним из них является объект d типа D, свойство fk которого имеет тип C.

Теперь, когда я получаю доступ к значению d.fk.c, Django запускает дополнительный запрос, чтобы получить свойства C:

'SELECT "mapping_a"."id", "mapping_a"."prop_a", "mapping_c"."a_ptr_id", "mapping_c"."prop_c" FROM "mapping_c" INNER JOIN "mapping_a" ON ("mapping_c"."a_ptr_id" = "mapping_a"."id") WHERE "mapping_c"."a_ptr_id" = 3'

Я хочу избежать этого дополнительного запросана объект D. Использование InheritanceManager предложенным способом, похоже, не позволяет этого.

1 Ответ

0 голосов
/ 16 ноября 2018

Я использую Inheritance Manager обычно и работает как положено.

1) Не забудьте установить менеджер наследования на A:

class A(models.Model):
    # ...
    objects = InheritanceManager()

2) Сделайте правильный запрос:

some_d_object = D.objects.get( pk = 1 )
related = some_d_object.fk.all().select_related()

Noticte than, ваш запрос D.objects.all().select_related() вернет D объектов. Никто не наследует от D, то есть никаких подклассов, только D объекты.

3) Наслаждайся наследством.

Отредактировано Я редактирую эту очередь, потому что комментарий OP.

С этим шаблоном Django выполняет дополнительный запрос БД, когда я получаю доступ к связанному объекту. Поскольку у меня много D-объектов, это становится довольно дорогим. Вы знаете, есть ли способ получить их всех сразу? -

Хорошо, давайте попробуем написать ответ, потому что я действительно не понимаю точно, какие объекты ищет ОП. Вопрос в порядке, потому что он написал почти пример Minimal, Complete и Verifiable , но я не знаю ожидаемых значений, давайте попробуем с некоторыми примерами.

1) Если вам нужны все объекты, просто:

all_objects = A.objects.all().select_subclasses()

2) Если вы хотите отфильтровать, сделайте это. Я пишу образец:

filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()

3) Получить все подклассы, а также класс D в одном запросе:

К сожалению, вы не можете подать заявку prefetch_related (может быть, вы можете, но я не знаю, как это сделать). Затем вам нужно скопировать данные с помощью itertools.

all_objects_and_D = list(
                     A
                     .objects
                     .select_related('D')
                     .select_subclasses()
                     .order_by( 'D__pk' )
                     )
#at this point use itertools to massage your data
keyfunc = lambda x: x.D
data = [  { k, list(g) } 
          for k, g in 
          itertools.groupby(all_objects_and_D, key=keyfunc )
       ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...