Это кровотечения-ребро, что я'м на вертеле и быстро истекал кровью. Я хочу, чтобы аннотировать подзапрос-совокупность на существующий объект QuerySet. Делаем это до 1.11 или имел в виду пользовательские SQL или долбят базу. Здесь'ы в документации на это, и пример из нее:
from django.db.models import OuterRef, Subquery, Sum
comments = Comment.objects.filter(post=OuterRef('pk')).values('post')
total_comments = comments.annotate(total=Sum('length')).values('total')
Post.objects.filter(length__gt=Subquery(total_comments))
Они'ре аннотирование о агрегата, который кажется странным для меня, но это неважно.
Я'м борется с этим, поэтому я'м кипеть его обратно к простой реальный пример у меня есть данные для. У меня есть парковки, которые содержат много пространства. Забронировать используйте →автор, если это делает вас счастливее, но на сейчас— я просто хочу, чтобы аннотировать на счет модели, используя подзапрос
*.
spaces = Space.objects.filter(carpark=OuterRef('pk')).values('carpark')
count_spaces = spaces.annotate(c=Count('*')).values('c')
Carpark.objects.annotate(space_count=Subquery(count_spaces))
Это дает мне прекрасный `ProgrammingError: больше, чем одна строка возвращается вложенный запрос используется в качестве выражения и в моей голове, эта ошибка имеет смысл. Подзапрос возвращает список вместе с комментариями-на общее.
Пример предположили, что какое-то волшебное произойдет и я'd в итоге с какого числа я могу использовать. Но, что's не происходит? Как я могу комментировать по совокупности данных подзапроса?
Я построил новую модель парковки/пространство и это сработало. Поэтому на следующем этапе работы, что'ы отравление моем SQL. На Лорана'ы советы, я взглянул на SQL и постарались сделать его более похожим на версию они выложили в свой ответ. И это, где я нашел реальную проблему:
в <предварительно><код>выберите "и bookings_carpark" у.*, (Выберите граф(Ц0.&и"ИД") Смотрите как "с"и От "bookings_space на" Ц0 Где Ц0.&я carpark_id" и = (и"bookings_carpark и".&и"ИД" - а) Группы и U0.&я carpark_id" и в<сильный>, и U0.&"космос";</сильные> ) Как "space_count" и от "bookings_carpark на";</код></пре>
Я'вэ-подчеркнул он, но это's, что подзапрос'группа s ПО ... и U0.&"космос";
. Это'ы перенастройки оба по какой-то причине. Расследования продолжаются.
Правка 2: ок, просто глядя на подзапрос в SQL я вижу, что вторая группа, придя через ☹
In [12]: print(Space.objects_standard.filter().values('carpark').annotate(c=Count('*')).values('c').query)
SELECT COUNT(*) AS "c" FROM "bookings_space" GROUP BY "bookings_space"."carpark_id", "bookings_space"."space" ORDER BY "bookings_space"."carpark_id" ASC, "bookings_space"."space" ASC
Редактировать 3: Хорошо! Обе эти модели имеют сортировки. Это осуществляется через подзапрос. Это'с этих заказов, вздутие живота мой запрос и ломать его.
Я думаю, это может быть баг в Django, но хватает удаление мета-order_by на обе эти модели, есть ли способ я могу unsort запрос на querytime?
<суб>*я знаю, что я могу просто комментировать в данном примере число. Моя реальная цель для использования этого является значительно более сложный фильтр-счет, но я могу'т даже сделать это рабочим.ЛТ;/суб>
Shazaam! На мои правки, дополнительный столбец был выход из моей подзапрос. Это должно было облегчить заказ (который просто не'т необходимости в счет).
Мне просто нужно, чтобы удалить прописаны мета-приказ от модели. Вы можете сделать это, просто добавив пустой `.order_by () в подзапросе. В моих условиях код, который означает:
spaces = Space.objects.filter(carpark=OuterRef('pk')).order_by().values('carpark')
count_spaces = spaces.annotate(c=Count('*')).values('c')
Carpark.objects.annotate(space_count=Subquery(count_spaces))
И что работает. Великолепно. Так раздражает.
Это's также можно создать подкласс подзапрос
, что изменения в SQL это выходы. Например, вы можете использовать:
class SQCount(Subquery):
template = "(SELECT count(*) FROM (%(subquery)s) _count)"
output_field = models.IntegerField()
Затем вы используете это как если бы оригинальный подзапрос
класса:
spaces = Space.objects.filter(carpark=OuterRef('pk')).values('pk')
Carpark.objects.annotate(space_count=SQCount(spaces))
Вы можете использовать этот трюк (по крайней мере в Postgres) с диапазоном агрегирующих функций: я часто использую его, чтобы построить массив значений, или сложить их.
Я просто наткнулся на очень похожий случай, где мне пришлось вам бронировать места на мероприятия, статус заказ не отменен. После попытки решать проблему в течение нескольких часов, здесь's то, что я'вэ видел, как основную причину проблемы:
Предисловие: это MariaDB в, Джанго 1.11.
При аннотировании запрос, он получает группы
п. с полями выбора (в основном то, что's в значений ()
подбор запросов). После расследования с MariaDB в инструмент командной строки, почему я'м получаю значение null или нет на результаты запроса, я'вэ пришел к выводу, что группы
п. будет потому что функция count () "возвращает" нулевое по.
Затем, я начал заниматься дайвингом в объект QuerySetинтерфейс, чтобы увидеть, как я могу вручную, принудительно удалить
группы` от запросов к БД, и придумал следующий код:
from django.db.models.fields import PositiveIntegerField
reserved_seats_qs = SeatReservation.objects.filter(
performance=OuterRef(name='pk'), status__in=TAKEN_TYPES
).values('id').annotate(
count=Count('id')).values('count')
# Query workaround: remove GROUP BY from subquery. Test this
# vigorously!
reserved_seats_qs.query.group_by = []
performances_qs = Performance.objects.annotate(
reserved_seats=Subquery(
queryset=reserved_seats_qs,
output_field=PositiveIntegerField()))
print(performances_qs[0].reserved_seats)
Так в основном, вы должны вручную удалить/обновить поле group_by на подзапрос'ы объект QuerySet для того, чтобы не иметь группировать по
добавить его на выполнение. Также, вы'будете иметь, чтобы указать, что поле вывода подзапроса будет, как кажется, что Django не сможет автоматически распознать его и вызывает исключения, на первой оценки объект QuerySet. Интересно, что вторая оценка прошла успешно и без него.
Я считаю, что это ошибка Django или неэффективности в подзапросы. Я'Лл создать отчет об ошибке об этом.
Редактирование: отчет об ошибках здесь.
Если я правильно понял, вы пытаетесь считать пространство доступно в гараж
. Подзапрос кажется перебор для этого, старые добрые комментировать только **** следует сделать трюк:
Carpark.objects.annotate(Count('spaces'))
Это будет включать в себя пробелы__считайте значение в результатах.
ОК, я видел твою записку...
Я также смог запустить свой же запрос с другими моделями у меня был под рукой. Результаты такие же, поэтому запрос в вашем примере вроде нормально (проверено с Django 1.11b1):
activities = Activity.objects.filter(event=OuterRef('pk')).values('event')
count_activities = activities.annotate(c=Count('*')).values('c')
Event.objects.annotate(spaces__count=Subquery(count_activities))
Может быть, Вашу "простой реальный пример" это слишком просто... может вы поделитесь моделей или другая информация?
Решение, которое будет работать для любой общей агрегации может быть реализована через окно
классы с Django 2.0. Я добавил Это к билету трекер Джанго, а также.
Это позволяет обобщать аннотированный значений путем расчета совокупности по секциям на основе модели внешнего запроса (в группе by пункт), затем аннотирования данных для каждой строки в объект QuerySet подзапрос. Тогда подзапрос может использовать агрегированные данные из первой строки, возвращаемой и игнорировать другие строки.
Performance.objects.annotate(
reserved_seats=Subquery(
SeatReservation.objects.filter(
performance=OuterRef(name='pk'),
status__in=TAKEN_TYPES,
).annotate(
reserved_seat_count=Window(
expression=Count('pk'),
partition_by=[F('performance')]
),
).values('reserved_seat_count')[:1],
output_field=FloatField()
)
)
"У меня работает" и не'т очень сильно помочь. Но.
Я попробовал ваш пример на некоторые модели у меня был удобный тип (книга -> автор
), он работает нормально для меня в Django 1.11b1.
Вы уверены, что вы'повторно выполнить это в правильной версии Джанго? Это фактический код, который вы'вновь работает? Вы вообще тестировали не на автостоянки
, но некоторые более сложные модели?
Может, попробовать к печати(запрос.запроса), чтобы увидеть, что SQL это'ы пытались запустить в базе данных. Ниже то, что я получил с моей модели (отредактированы, чтобы соответствовать ваш вопрос):
SELECT (SELECT COUNT(U0."id") AS "c"
FROM "carparks_spaces" U0
WHERE U0."carpark_id" = ("carparks_carpark"."id")
GROUP BY U0."carpark_id") AS "space_count" FROM "carparks_carpark"
Не совсем ответ, но, надеюсь, это поможет.