#django #django-views #django-orm
#django #django-просмотры #django-orm
Вопрос:
У меня есть две таблицы:
class Product(models.Model):
code = models.ForeignKey(Product)
regularprice = models.DecimalField (max_digits=8, decimal_places=2)
class Override(models.Model):
productcode = models.ForeignKey(Product)
specialprice = models.DecimalField (max_digits=8, decimal_places=2)
Data Example
============
Product
Code RegularPrice
C101 1.25
C102 2.50
C103 3.00
Override
ProductCode SpecialPrice
C102 1.50
Я хочу сделать эквивалент левого внешнего соединения. Результирующий набор, которого я хочу достичь, будет:
Code RegularPrice SpecialPrice
C101 1.25 NULL
C102 2.50 1.50
C103 3.00 NULL
Как бы я это сделал?
РЕДАКТИРОВАТЬ: я пытаюсь получить базовый прайс-лист с необязательными значениями переопределения. Генерируются базовые цены, к которым добавляются любые значения переопределения (или NULL, если их нет).
Очень жаль, но я пропустил важный элемент этого вопроса, думая, что это упростит его. У каждого переопределения есть столбец с именем Customer . Класс переопределения имеет УНИКАЛЬНЫЕ ЗНАЧЕНИЯ для «customerid» и «code» (так что одно переопределение для каждого кода для каждого клиента).
Я хочу создать прайс-лист всех продуктов , если для конкретного клиента присутствуют какие-либо переопределения, они будут показаны вместе с соответствующей линейкой продуктов.
Запрос ORM выглядит следующим образом: pricelist = Product.objects.select_related().filter(переопределить__customerid=1)
Но это выполняет только обычное соединение (исключая любой продукт, который не связан с переопределением), я хочу, чтобы ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ отображало все в таблице продуктов, с присоединением любых переопределений (если они присутствуют или NULL)
Большое спасибо за любую помощь, которую вы можете предложить!
Ответ №1:
В каком контексте? Если все, что вы хотите сделать, это распечатать это, вы можете просто использовать:
products = Product.objects.all()
или любой Product
другой запрос, который вы хотите, затем выполните цикл в шаблоне, например:
{% for product in products %}
{{product.code}}
{{product.regularprice}}
{{product.override.specialprice|default:"NULL"}}
{% endfor %}
Если вам нужен более эффективный запрос к базе данных, вы можете использовать select_related
(docs):
products = Product.objects.select_related('override')
но это будет работать, только если вы используете OneToOneField
for productcode
, а не a ForeignKey
:
class Override(models.Model):
productcode = models.OneToOneField(Product)
Комментарии:
1. select_related не может следовать обратным связям. Вы вроде бы заметили, что … но то, что вы показываете, просто не будет работать
2.@John — согласно документам,
select_related
может следовать обратным связям, но только дляOneToOneField
s, как я отмечаю в своем ответе (я подчеркну это немного больше, если это поможет). Похоже, что использование aOneToOneField
может быть вполне разумным вариантом в случае OP.3. В целом следует избегать OneToOneFields. Они представляют собой ненужное соединение для данных, которые вы, скорее всего, должны иметь только в основной модели. Единственное реальное хорошее применение для них — это если у вас есть какое-то подмножество данных, которое действительно дорого извлечь из базы данных и редко используется. С учетом сказанного, мое чтение моделей подразумевает, что у него один ко многим, и он может этого не осознавать
4. Большое спасибо за ответ, я вижу, что пропустил важную информацию и пересмотрел свой вопрос.
Ответ №2:
В зависимости от того, что вы настроили, связь между Product и Override является одним из многих. Это означает, что для каждого продукта у вас будет (потенциально) много переопределений.
Итак, теперь вам нужно подумать о том, что вы хотите сгенерировать, и это определит, как вы хотите запросить это.
Если вам нужен список переопределений, просто запросите Override.objects.all().select_related()
Затем вы можете сгенерировать список переопределений и связанных с ними данных продукта, следуя foreignkeys:
o = Override.objects.all()[0]
o.product.regularprice
Если вам нужен список продуктов, каждый из которых имеет свой собственный список переопределений, вам следует посмотреть на функцию itertools grouby (или, если вы находитесь в шаблоне, используйте regroup
тег django)
Комментарии:
1. Большое спасибо за ответ, но я пропустил важную информацию, я пересмотрел свой вопрос.
Ответ №3:
Я считаю, что в настоящее время это невозможно с ORM Django, и вам нужно использовать raw
запрос.