Рассмотрим ниже пример:Создание пользовательского запроса в Django 1.8
class Customer(models.Model):
first_name = models.CharField()
last_name = models.CharField()
rental_date = models.DateTimeField()
rented_car = models.ForeignKey(Car)
class Car(models.Model):
color = models.CharField()
reg_no = models.IntegerField()
Я хочу, чтобы сгруппировать все объекты недвижимости на машине (при условии, что клиент не может арендовать больше, чем один автомобиль, но клиент может взять напрокат автомобиль несколько раз) и для каждой группы возвращаются только арендные платежи с самыми последними rental_date
и получают доступ к имени заказчика и автомобилю reg_no
.
SQL, будет выглядеть примерно так:
SELECT * FROM Customer c where rental_date = (SELECT max(rental_date) FROM Customer WHERE rented_car_id = c.rented_car_id);
или как это:
SELECT *, max(rental_date) from Customer group by rented_car;
Приведенное запрос посаженные затем будет отсортирован по first_name клиента или автомобиля reg_no и другие фильтры могут быть (например, получение только синих автомобилей или клиентов, чье имя начинается с «A»).
Вещи, которые я пытался:
Aggregation:
from django.db.models Max
Customer.objects.values('rented_car').annotate(max_start_date=Max('rental_date'))
но это возвращает Dict, содержащий первичные ключи Car
объектов. Мне нужны значения от Customer
. Изменение запроса для включения поля из Customer
(.values('rented_car', 'first_name')
) изменит SQL и изменит окончательный результат.
Второй метод я использовал raw
:
Customer.objects.raw("""SELECT * FROM Customer c where rental_date = (SELECT max(rental_date) FROM Customer WHERE rented_car_id = c.rented_car_id)""")
но это возвращает экземпляр RawQuerySet, который не позволяет дальнейшую фильтрацию или упорядочение. Кроме того, Customer.objects.filter(...).raw(...).order_by(...)
не будет работать, поскольку метод raw
переопределит фильтрацию.
Другой метод, который может вернуть запрос набора и позволяет использовать дополнительные фильтрации extra
:
Customer.objects.filter(...).extra(select={
'customer_instances': """SELECT *, max(rental_date) from Customer group by rented_car"""
})
, но его всегда будет возвращать ошибку (1241, 'Operand should contain 1 column(s)')
. Кроме того, из этого discussion я обнаружил, что QuerySet.extra (...) больше не будет иметь поддержки, а вместо этого следует использовать aggregation
.
Ваша модель/схема кажется мне довольно странной - я бы использовал промежуточную модель «Rent» с датой и внешними ключами на «Car» и «Customer». –
Благодарим за отзыв. Однако это аналогия ситуации, которую я имею в проекте, над которым я работаю. В связи с соглашениями NDA, я не могу дать более подробную информацию, однако, если бы другая модель не была подходящей. –
Почему ваш проект не принял разумный дизайн базы данных? Кроме того, если вы находитесь под строгими NDA и т. Д., Тогда есть деньги, поэтому нанимайте консультанта, который знает свой путь вокруг Django и SQL, и не приходят сюда, прося других людей сделать ваши вакансии бесплатно. –