Как выполнять запросы в Django после отношений двойного соединения (или: Как обойти ограничения Django на ManyToMany «Сквозные» модели?)

Должен быть способ выполнить этот запрос через ORM, но я его не вижу.

Настройка

Вот что я моделирую: один арендатор может занимать несколько комнат и один Пользователь может владеть несколькими комнатами. Таким образом, у комнат есть FK для арендатора и FK для пользователя. Комнаты также обслуживаются (возможно, отдельным) пользователем.

То есть у меня есть эти (упрощенные) модели:

class Tenant(models.Model):
    name = models.CharField(max_length=100)

class Room(models.Model):
    owner = models.ForeignKey(User)
    maintainer = models.ForeignKey(User)
    tenant = models.ForeignKey(Tenant)

Проблема

Учитывая арендатора, я хочу, чтобы пользователи владели комнатой, которую они занимают.

Соответствующий запрос SQL будет следующим:

SELECT auth_user.id, ...
FROM tenants_tenant, tenants_room, auth_user
WHERE tenants_tenant.id = tenants_room.tenant_id
AND tenants_room.owner_id = auth_user.id;

Получение любого индивидуального значения из связанных объектов пользователя может быть выполнено с помощью, например, my_tenant.rooms.values_list ('owner__email', flat = True) , но получение полного набора запросов пользователей сбивает меня с толку.

Обычно одним из способов решения этой проблемы является настройка поле ManyToMany в моей модели Tenant , указывающее на пользователя с TenantRoom в качестве сквозной модели. Однако в данном случае это не сработает, поскольку модель TenantRoom имеет второго (несвязанного) ForeignKey - пользователя ( см. «Ограничения» ). Кроме того, это кажется ненужным беспорядком в модели арендатора.

Выполнение my_tenant.rooms.values_list ('user', flat = True) приближает меня, но возвращает ValuesListQuerySet идентификаторов пользователей, а не набор запросов фактических объектов User.

Вопрос

Итак: есть ли способ получить набор запросов фактических экземпляров модели через ORM, используя всего один запрос?


Изменить

Если на самом деле нет способа сделать это напрямую в одном запросе через ORM, какой лучший (какая-то комбинация наиболее производительного, наиболее идиоматического, наиболее читаемого и т. д.) способа выполнить то, что я ищу? Вот варианты, которые я вижу:

  1. Подвыбор

     users = User.objects.filter (id__in = my_tenant.rooms.values_list ('user')) flat = True)  приближает меня, но возвращает ValuesListQuerySet идентификаторов пользователей, а не набор запросов фактических объектов User. 
    
    

    Вопрос

    Итак: есть ли способ получить набор запросов фактических экземпляров модели через ORM, используя только один запрос?


    Изменить

    Если на самом деле нет способа сделать это напрямую в одном запросе через ORM, какой лучший (какая-то комбинация наиболее производительного, наиболее идиоматического, наиболее читаемого и т. д.) способа выполнить то, что я ищу? Вот варианты, которые я вижу:

    1. Подвыбор

       users = User.objects.filter (id__in = my_tenant.rooms.values_list ('user')) flat = True)  приближает меня, но возвращает ValuesListQuerySet идентификаторов пользователей, а не набор запросов фактических объектов User. 
      
      

      Вопрос

      Итак: есть ли способ получить набор запросов фактических экземпляров модели через ORM, используя всего один запрос?


      Изменить

      Если на самом деле нет способа сделать это напрямую в одном запросе через ORM, какой лучший (какая-то комбинация наиболее производительного, наиболее идиоматического, наиболее читаемого и т. д.) способа выполнить то, что я ищу? Вот варианты, которые я вижу:

      1. Подвыбор

         users = User.objects.filter (id__in = my_tenant.rooms.values_list ('user')) используя только один запрос? 
        
        

        Edit

        Если на самом деле нет способа сделать это напрямую в одном запросе через ORM, что лучше (какая-то комбинация наиболее производительного, наиболее идиоматического, наиболее читаемого и т. д. .) способ выполнить то, что я ищу? Вот варианты, которые я вижу:

        1. Подвыбор

           users = User.objects.filter (id__in = my_tenant.rooms.values_list ('user')) используя только один запрос? 
          
          

          Edit

          Если на самом деле нет способа сделать это напрямую в одном запросе через ORM, что лучше (какая-то комбинация наиболее производительного, наиболее идиоматического, наиболее читаемого и т. д. .) способ выполнить то, что я ищу? Вот варианты, которые я вижу:

          1. Подвыбор

             users = User.objects.filter (id__in = my_tenant.rooms.values_list ('user'))
            
          2. Подвыбор с помощью Python (см. Рекомендации по производительности для объяснения этого)

             user_ids = id__in = my_tenant.rooms.values_list ('user')
            users = User.objects.filter (id__in = list (user_ids))
            
          3. Необработанный SQL:

             User.objects.all ("" "SELECT auth_user. *
            ОТ tenants_tenant, tenants_room, auth_user
            ГДЕ tenants_tenant.id = tenants_room.tenant_id
            И tenants_room.owner_id = auth_user.id "" ")
            
          4. Другое ...?

5
задан Gabriel Grant 27 January 2011 в 03:57
поделиться