Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Join той же таблицы в Django ORM

#sql #django


Есть две модели - Покупатель и Заказ:

class Customer(AbstractUser):
    pass


class Order(models.Model):
    SHOP_1, SHOP_2, SHOP_3 = 1, 2, 3
    SHOP_CHOICES = (
        (SHOP_1, 'Shop 1'),
        (SHOP_2, 'Shop 2'),
        (SHOP_3, 'Shop 3'),
    )

    customer = models.ForeignKey(Order, related_name='orders')
    shop = models.IntegerField(choices=SHOP_CHOICES)
    updated_dt = models.DateTimeField(auto_now=True)
    price = models.DecimalField()


Надо по каждому пользователю вывести последние заказы по каждому магазину. То есть
из этого:

Customer
+-----+----------+
| id  | username |
+-----+----------+
| 1   | Garry    |
| ... | ...      |
+-----+----------+

Order
+-----+-------------+------+---------------------+-------+
| id  | customer_id | shop | updated_dt          | price |
+-----+-------------+------+---------------------+-------+
| 1   | 1           | 1    | 2017-07-01 00:00:00 | 12    |
| 2   | 1           | 1    | 2017-07-02 00:00:00 | 23    |
| 3   | 1           | 2    | 2017-07-01 00:00:00 | 35    |
| 4   | 1           | 2    | 2017-07-02 00:00:00 | 23    |
| 5   | 1           | 2    | 2017-07-03 00:00:00 | 93    |
| 6   | 1           | 3    | 2017-07-04 00:00:00 | 230   |
| ... | ...         | ...  | ...                 | ...   |
+-----+-------------+------+---------------------+-------+


Надо получить это:

+-----+-------------+------+---------------------+-------+
| id  | customer_id | shop | updated_dt          | price |
+-----+-------------+------+---------------------+-------+
| 2   | 1           | 1    | 2017-07-02 00:00:00 | 23    |
| 5   | 1           | 2    | 2017-07-03 00:00:00 | 93    |
| 6   | 1           | 3    | 2017-07-04 00:00:00 | 230   |
+-----+-------------+------+---------------------+-------+


Есть идея реализовать данный вывод через join таблицы заказов к этой же таблице:

SELECT 
  order1.*
FROM order order1
  LEFT JOIN order order2 ON (order1.shop = order2.shop
                             AND order1.updated_dt < order2.updated_dt
                             AND order1.customer_id = order2.customer_id)
WHERE stat2.id IS NULL AND stat1.customer_id = 1;


Но, насколько я понимаю, в Django нельзя явно join'ить таблицы.
    


Ответы

Ответ 1



Несколько лет не аботал с django. Раньше это делалось так: class Order(models.Model): SHOP_1, SHOP_2, SHOP_3 = 1, 2, 3 SHOP_CHOICES = ( (SHOP_1, 'Shop 1'), (SHOP_2, 'Shop 2'), (SHOP_3, 'Shop 3'), ) customer = models.ForeignKey('Order', related_name='orders') shop = models.IntegerField(choices=SHOP_CHOICES) updated_dt = models.DateTimeField(auto_now=True)

Ответ 2



Есть наивный вариант: Order .object .filter(customer__id=1) .values("shop") .annotate( id=Max("id"), customer_id=Max("customer_id"), updated_dt=Max("updated_dt") ) В данном случае мы сначала делаем группировку по магазину, а далее выбираем максимальную дату и оборачиваем все остальные колонки в аггрегирующие функции. Работа с аггрегированием описанна в документации: https://docs.djangoproject.com/en/dev/topics/db/aggregation/#order-of-annotate-and-values-clauses If the values() clause precedes the annotate(), the annotation will be computed using the grouping described by the values() clause. However, if the annotate() clause precedes the values() clause, the annotations will be generated over the entire query set. In this case, the values() clause only constrains the fields that are generated on output.

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

Отправить комментарий