#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 становится промежуточной моделью, которая эффективно связывает внешние ключи пользователя и сайта в составной ключ, предоставляя каждой уникальной комбинации пользователя и сайта собственный идентификатор. Затем мы можем перемещаться вперед и назад между моделями, которые используют пользовательский сайт для связи данных. Очень умно!