Django не поддерживает «соединения» в обычном смысле SQL - он поддерживает навигацию по объектам.
Обратите внимание, что реляционное соединение (внутреннее или внешнее) создает новый "класс" сущностей. Тот, который не имеет определения в Джанго. Так что нет правильного «набора результатов», так как нет определения класса для вещей, которые вы возвращаете. Лучшее, что вы можете сделать, это определить кортеж, который будет упакован с None для пропущенных комбинаций.
Левое (или правое) внешнее соединение выглядит следующим образом. Он создает два непересекающихся подмножества: те, у кого есть связанный набор связанных сущностей, и те, у кого его нет.
for obj in Model1.objects.all():
if obj.model2_set().count() == 0:
# process (obj, None) -- no Model2 association
else:
for obj2 in obj.model2_set.all():
# process (obj, obj2) -- the "inner join" result
«Полное» внешнее объединение - это объединение оставшихся элементов, которые не имеют отношений.
for obj2 in Model2.objects.all():
if obj2.model1_set().count() == 0:
# process (None, obj2) -- no Model1 association
Проблема всегда в том, какую обработку вы выполняете с этой странной коллекцией трех разных подмножеств объектов?
Задача объектной базы данных - сосредоточить обработку на объекте и связанных с ним объектах.
Своеобразный набор, называемый «реляционным объединением», никогда не входит в исходную объектную модель. Это новый класс объектов, созданный из двух (или более) оригинальных объектов.
Хуже того, внешние объединения создают коллекцию с несколькими подклассами (внутреннее соединение, левое внешнее соединение и правое внешнее соединение). Что означает этот набор вещей ?
Подождите, может быть хуже. Если обработка включает проверку отсутствующих атрибутов (например, if someObj.anObj2attribute is None
: мы, по сути, ищем Model1
элементов, с которыми не связан Model2
объект. Ммм ... почему мы поместили их во внешнее соединение, только для фильтрации они используют оператор if
. Почему бы просто не выполнить отдельные запросы и правильно обработать каждое подмножество?
Редактировать: Когда вы показываете "неполный" статус, это вообще не внешнее соединение. Это намного проще. Вам нужно создать одну (или две) отдельные коллекции в функции просмотра для отображения вашего шаблона.
Во-первых, вы должны использовать коды состояния, а не наличие или отсутствие внешнего ключа. Необязательные внешние ключи не имеют «причин» - они либо есть, либо их нет. Код состояния может предоставлять полезные оттенки значения («неполное», «по ошибке», «сломано», «не применимо», «подлежит удалению» и т. Д.)
errorList1 = Model1.objects.filter( status="Incomplete" )
errorList2 = Model2.objects.filter( status="Incomplete" )
Это две неприсоединяемые части полного внешнего соединения. Затем вы можете отобразить эти два списка ошибок в своем шаблоне с соответствующими заголовками столбцов и кодами состояния и всем прочим.
Вы даже можете поместить их в одну таблицу, чтобы имитировать старый полный отчет о внешнем объединении, который раньше видели люди
<table>
<tr><th>Model1</th><th>Model2</th></tr>
{% for e1 in errorList1 %}
<tr><td>e1</td><td>NULL</td></tr>
{% endfor %}
{% for e2 in errorList2 %}
<tr><td>NULL</td><td>e2</td></tr>
{% endfor %}
</table>
Выглядит как полный отчет о внешнем соединении. Без полного внешнего соединения.