Множественное левое и левое объединение для одного и того же модельного необработанного запроса конвертируется в Django ORM - PullRequest
0 голосов
/ 29 декабря 2018

Использование Django 1.11

У меня есть следующие модели:

class Vendor(Model):

class Product(Model):

class Pricebook(Model):

class Quote(Model):
     vendor = models.ForeignKey(Vendor)

class SKU(Model):
     product = models.ForeignKey(Product)
     pricebook = models.ForeignKey(Pricebook)
     vendor    = models.ForeignKey(Vendor)

class SKUPrice(Model):
    sku = models.ForeignKey(SKU, related_name="prices")

class LineItem(Model):
    quote = models.ForeignKey(Quote, related_name="quote_line_items")
    sku = models.ForeignKey(SKU)

Это необработанный запрос, который работает для меня.

SELECT 
  qli.quantity, 
  sku_source.product_id, 
  sku_dest.id as sku_dest_id, 
  sku_dest_price.id as sku_dest_price_id 
FROM lineitem qli 
INNER JOIN sku sku_source ON 
  qli.sku_id = sku_source.id 
LEFT JOIN sku sku_dest ON 
  sku_dest.pricebook_id = sku_source.pricebook_id AND
  sku_dest.product_id = sku_source.product_id 
LEFT JOIN skuprice sku_dest_price ON
  sku_dest_price.status = 'default' AND 
  sku_dest_price.sku_id = sku_dest.id
WHERE qli.quotation_id = 40 AND 
  qli.quantity > 0 AND 
  sku_dest.vendor_id = 38;

Что я пробовалis:

(the_quote_with_id_as_40
.quotation_line_items
.filter(quantity__gt=0)
.select_related('sku__product')
.values('sku__product__id', 'quantity')
)

Это производит этот запрос

SELECT "sku"."product_id", "lineitem"."quantity"
FROM "lineitem" 
INNER JOIN "sku" ON ("lineitem"."sku_id" = "sku"."id") 
WHERE ("lineitem"."quotation_id" = 40 AND 
       "lineitem"."quantity" > 0)

, что не совсем то, что я хочу.

Я, конечно, могу использовать необработанный запрос.Но я хотел бы знать, если возможно использовать ORM.По крайней мере, это для расширения моих знаний.

Спасибо.

ОБНОВЛЕНИЕ

Поскольку есть просьба уточнить мои модели, япишу следующее.

У меня есть объект Quote.Это позволяет много объектов LineItem.Каждый LineItem один-ко-многим с SKU и Quote.

Артикул принадлежит Ценовой книжке, Продукту и Продавцу.Это описание отношения также можно почерпнуть из приведенного выше кода.

Но для ясности я повторю здесь.

Эта схема такова, что один и тот же Продукт может быть продан разными Продавцами, но они будут выглядеть как разные SKU.

Это специально.

Наш вариант использования следующий: пользователь пытается скопировать элементы LineItem отдельной цитаты в другую цитату.

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

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

Проблема заключается в следующем.Теперь у нас есть две цитаты (исходная цитата для копирования и целевая цитата для копирования).Обе цитаты могут иметь одного и того же продавца.Или они не могут.Пользователь хочет, чтобы мое приложение Django автоматически обслуживало обе ситуации.

Так что это означает, что мне нужно выяснить следующее, прежде чем дублировать.

  • количество, указанное в LineItem
  • Продукт, как указано в LineItem по отношению к SKU
  • , находит соответствующий SKU, проданный Продавцом для цены назначения
  • и соответствующую цену за единицу

Необработанный запрос позволяет мне извлечь все 4 фрагмента информации в одном запросе.Это эффективно.

Следовательно, вы видите, что у меня есть псевдоним sku_source и sku_dest

Вот почему мои критерии WHERE содержат 3 условия:

  1. будут скопированы только исходные элементы LineItems с количеством> 0
  2. будут скопированы только строки LineItems из определенного исходного предложения
  3. только SKU, предназначенные для конкретного поставщика (в данном случае поставщик для конечного предложения) будет рассмотрено

Возможно, что:

  1. несколько LineItems для одного и того же продукта (по отношению к SKU) появятся в одном источникеЦитата.

  2. Поставщик пункта назначения (имеется в виду Продавец пункта назначения) не продает конкретный Продукт, который продает Поставщик источника.Поэтому я использую LEFT JOIN.Это означает, что данный конкретный продукт не будет продублирован.

Надеюсь, это прояснит ситуацию.

1 Ответ

0 голосов
/ 05 января 2019

Для меня неправильный подход к проблеме.

Вы все еще пытаетесь объяснить запрос, а не объекты, которые вам нужны.При работе с ORM вам нужно перестать думать о запросе и начать думать об объектах и ​​о том, как они могут играть / взаимодействовать друг с другом.Тем самым вы поместите свою бизнес-логику в свой код (модели, менеджеры и т. Д.), А не в свои запросы.Вы не хотите использовать бизнес-логику в запросе, а затем начать думать: хорошо, как мне создать этот запрос сейчас?Умные объекты с тупыми запросами легче оптимизировать и понимать другими, чем умные запросы с тупым кодом (объектами).

Начните с объектов, напишите свой код, а затем оптимизируйте его.

Если вы покажете мне неоптимизированную объектно-ориентированную версию того, как / что вам нужно для создания этих дубликатов, я, вероятно, смогу показать вам, как вы можете ее оптимизировать.

До тех пор, и не для того, чтобы быть полностью не по теме, попробуйте этот запрос, но я не могу дать никаких гарантий, что это то, что вы ищете:

quote.quotation_line_items.filter(
    quantity__gt=0,
    sku__vendor__sku__vendor=38,
    sku__vendor__sku__product=models.F('sku__product'),
    sku__vendor__sku__pricebook=models.F('sku__pricebook'),
).values(
    'quantity',
    'sku__product_id', # sku source product_id
    'sku__vendor__sku__id', # sku dest id
    'sku__vendor__sku__skuprice__id' # sku dest skuprice id
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...