В Django, как мне соединить таблицу с составным первичным ключом с другой таблицей?

#python #django #left-join #composite-primary-key

#python #django #левое соединение #составной первичный ключ

Вопрос:

Вот что у меня есть на пути моделей:

 class Lead(models.Model):
    user = models.ForeignKey(User, related_name='leads')
    site = models.ForeignKey(Site)
    ...

class UserDemographic(models.Model):
    user = models.ForeignKey(User, related_name='user_demographic')
    site = models.ForeignKey(Site)
    ...

    class Meta:
        unique_together = 'user', 'site'
 

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

Что я хотел бы иметь возможность сделать, так это привязать эти демографические данные к нашему запросу потенциальных клиентов. У каждого интереса есть как пользователь, так и сайт, и я хочу получить данные из демографической таблицы и связать их с соответствующим интересом. Так что в основном то, что мне здесь нужно, — это левое соединение, которое объединит эти два элемента. Это достаточно просто сделать, когда есть только один внешний ключ, но я понятия не имею, как заставить его работать, когда есть два внешних ключа, с помощью которых можно объединить таблицы.

Есть идеи по этому поводу? Есть ли вообще способ сделать это в Django, или мне придется прибегнуть к необработанному запросу? Спасибо!

Ответ №1:

ORM Django не позволяет вам делать это изначально, но вы можете минимизировать свой необработанный sql, используя extra метод. Что-то вроде этого должно сработать:

 Lead.objects.extra(tables=['appname_userdemographic'], 
                   where=['appname_userdemographic.user_id=appname_lead.user_id',
                          'appname_userdemographic.site_id=appname_lead.site_id'],
                   select={'country': 'appname_userdemographic.country'})
 

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

 class UserSite(models.Model):
    user = models.ForeignKey(User)
    site = models.ForeignKey(Site)

class Lead(models.Model):
    user_site = models.OneToOneField(UserSite)
    ...

class UserDemographic(models.Model):
    user_site = models.OneToOneField(UserSite)
    ...
 

Затем вы можете использовать select_related , например:

 Lead.objects.select_related('usersite__userdemographic')
 

Комментарии:

1. Хм. Это немного удивительно, что у них нет чего-то встроенного. Кажется, это довольно распространенная вещь, которую приходится делать. Мне было любопытно узнать о вашем предложении на сайте пользователя, и я не совсем уверен, что вы имеете в виду. Думаю, вы могли бы привести короткий пример?

2. Кроме того, опробовал ваше предложение выше. Он работает, чтобы возвращать все нормально, когда в UserDemographic есть данные, но когда их нет, результатов нет. Так что это фактически внутреннее соединение. Есть ли способ выполнить левое соединение с помощью extra?

3. Хорошо, извините, я думаю, вам не повезло — разработчики ядра Django упорно отказывались добавлять какие-либо пользовательские возможности соединения слева в ORM: см code.djangoproject.com/ticket/7231 . Я обновлю свой ответ некоторыми подробностями.

4. А, понятно. Таким образом, в основном UserSite становится промежуточной моделью, которая эффективно связывает внешние ключи пользователя и сайта в составной ключ, предоставляя каждой уникальной комбинации пользователя и сайта собственный идентификатор. Затем мы можем перемещаться вперед и назад между моделями, которые используют пользовательский сайт для связи данных. Очень умно!