gpt4 book ai didi

Django REST framework 按字段分组并添加额外内容

转载 作者:行者123 更新时间:2023-12-03 23:53:04 25 4
gpt4 key购买 nike

我有一个订票模型

class Movie(models.Model):
name = models.CharField(max_length=254, unique=True)

class Show(models.Model):
day = models.ForeignKey(Day)
time = models.TimeField(choices=CHOICE_TIME)
movie = models.ForeignKey(Movie)

class MovieTicket(models.Model):
show = models.ForeignKey(Show)
user = models.ForeignKey(User)
booked_at = models.DateTimeField(default=timezone.now)

我想用它的 user 过滤 MovieTicket字段并根据其 show 对它们进行分组字段,并按最近预订的时间排序。并回复 json使用 Django REST 框架的数据,如下所示:
[
{
show: 4,
movie: "Lion king",
time: "07:00 pm",
day: "23 Apr 2017",
total_tickets = 2
},
{
show: 7,
movie: "Gone girl",
time: "02:30 pm",
day: "23 Apr 2017",
total_tickets = 1
}
]

我试过这种方式:
>>> MovieTicket.objects.filter(user=23).order_by('-booked_at').values('show').annotate(total_tickets=Count('show'))
<QuerySet [{'total_tickets': 1, 'show': 4}, {'total_tickets': 1, 'show': 4}, {'total_tickets': 1, 'show': 7}]>

但它不是根据节目分组的。另外我如何添加其他相关字段(即 show__movie__nameshow__day__dateshow__time )

最佳答案

我解释一下更一般的在数据库模型图上。它可以应用于任何具有额外内容的“GROUP BY”。

          +-------------------------+
| MovieTicket (booked_at) |
+-----+--------------+----+
| |
+---------+--------+ +--+---+
| Show (time) | | User |
++----------------++ +------+
| |
+------+-------+ +-----+------+
| Movie (name) | | Day (date) |
+--------------+ +------------+

问题是 :如何汇总由用户(其他相关对象)过滤的 Show(一个相关对象)分组的 MovieTicket(最顶层对象),以及来自一些相关更深层次对象(电影和日)的报告详细信息,并按从最顶层聚合的某些字段对这些结果进行排序群模(按群内最近MovieTicket的预约时间):

答案由更一般的步骤解释:
  • 从最上面的模型开始:(MovieTicket.objects ...)
  • 应用过滤器:.filter(user=user)
  • pk 分组很重要最接近的相关模型(至少是那些没有被过滤器固定的模型) - 它只是“显示”(因为“用户”对象仍然被过滤到一个用户).values('show_id')即使所有其他字段都是唯一的(show__movie__name、show__day__date、show__time),数据库引擎优化器最好按 show_id 对查询进行分组,因为所有这些其他字段都依赖于 show_id 并且不会影响组的数量。
  • 注释必要的聚合函数:.annotate(total_tickets=Count('show'), last_booking=Max('booked_at'))
  • 添加必需的依赖字段:.values('show_id', 'show__movie__name', 'show__day__date', 'show__time')
  • 对需要的东西进行排序:.order_by('-last_booking') (从最新到最旧)
    在没有通过聚合函数封装它的情况下,不要输出或排序最顶层模型的任何字段是非常重要的。 ( MinMax 函数适用于从组中采样某些内容。未由聚合封装的每个字段都将添加到“分组依据”列表中,这将破坏预期的组。可以为 friend 提供更多同一节目的门票逐渐预订,但应一起计算并以最新预订报告。)

  • 放在一起:
    from django.db.models import Max

    qs = (MovieTicket.objects
    .filter(user=user)
    .values('show_id', 'show__movie__name', 'show__day__date', 'show__time')
    .annotate(total_tickets=Count('show'), last_booking=Max('booked_at'))
    .order_by('-last_booking')
    )

    查询集很容易 转换为 JSON 如何演示 zaphod100.10在他的回答中,或者直接针对对 django-rest 框架不感兴趣的人:
    from collections import OrderedDict
    import json

    print(json.dumps([
    OrderedDict(
    ('show', x['show_id']),
    ('movie', x['show__movie__name']),
    ('time', x['show__time']), # add time formatting
    ('day': x['show__day__date']), # add date formatting
    ('total_tickets', x['total_tickets']),
    # field 'last_booking' is unused
    ) for x in qs
    ]))

    验证查询:

    >>> print(str(qs.query))

    SELECT app_movieticket.show_id, app_movie.name, app_day.date, app_show.time,
    COUNT(app_movieticket.show_id) AS total_tickets,
    MAX(app_movieticket.booked_at) AS last_booking
    FROM app_movieticket
    INNER JOIN app_show ON (app_movieticket.show_id = app_show.id)
    INNER JOIN app_movie ON (app_show.movie_id = app_movie.id)
    INNER JOIN app_day ON (app_show.day_id = app_day.id)
    WHERE app_movieticket.user_id = 23
    GROUP BY app_movieticket.show_id, app_movie.name, app_day.date, app_show.time
    ORDER BY last_booking DESC

    备注:
  • 模型图类似于多对多关系,但 MovieTickets 是单独的对象,可能包含座位号。
  • 通过一个查询,很容易为更多用户获得一份类似的报告。字段“user_id”和名称将添加到“values(...)”。
  • 相关模型 Day 不直观,但很明显它有一个字段 date希望还有一些非平凡的领域,可能对于安排与电影假期等事件有关的节目很重要。将字段“日期”设置为 Day 的主键会很有用在像这样的许多查询中频繁地建模和备用关系查找。

  • (这个答案的所有重要部分都可以在最旧的两个答案中找到: Todor 和 zaphod100.10。不幸的是,这些答案没有结合在一起,然后除了我之外没有被任何人投票,即使这个问题有很多-投票。)

    关于Django REST framework 按字段分组并添加额外内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43574335/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com