【问题标题】:Django query on event list: finding most recent events事件列表上的 Django 查询:查找最近的事件
【发布时间】:2021-02-16 19:44:02
【问题描述】:

我有一个收集事件的 django 模型。大致是这样的:

class Events(models.Model):
    class EventType(models.TextChoices):
        OPEN = ...
        CLOSE = ...
        OTHER = ...
        READ = ...

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    box = models.ForeignKey(Box, on_delete=models.CASCADE)
    event_timestamp = models.DateTimeField(default=django.utils.timezone.now)
    event_type = models.CharField(max_length=6, choices=EventType.choices)

当用户用盒子做事时会发生事件。

我有四个非常相关的查询要执行,如果不使用 SQL,我完全不确定如何执行此操作,这通常不是 django 的正确解决方案。

  1. 对于框 B 和用户 U,用户是最近打开还是关闭了此框?
  2. 对于 Box B,有多少用户处于打开状态?
  3. 对于框 B,我想绘制每天有多少用户打开,因此我想获得一组每天打开和关闭的用户。
  4. 我想要一个表格,显示处于打开状态的用户数量。

例如,在 SQL 中,这些将具有类似这样的形式(未经测试的代码,我希望使用 django 的查询语言更容易):

-- 1
SELECT event_type FROM Events
WHERE event_type in ('OPEN', 'CLOSE')
  AND user = U
HAVING max(event_timestamp);

-- 2
SELECT count(*) FROM (
    SELECT user, event_type FROM Events
    WHERE event_type in ('OPEN', 'CLOSE')
    GROUP BY user
    HAVING max(event_timestamp)
) as T
WHERE event_type = 'OPEN';

-- 3
// A bit complicated any way I slice it due to the
// mapping from datetime to date.

-- 4
SELECT box, count(user) FROM (
    SELECT box, user, event_type FROM Events
    WHERE event_type in ('OPEN', 'CLOSE')
    GROUP BY box, user
    HAVING max(event_timestamp)
) as T
WHERE event_type = 'OPEN'
GROUP BY box;

我已经解释了我的四个用例,但我怀疑一旦我理解了其中一个,其他的就会随之而来。显然,我只是没有从文档中摸索出一些东西(我希望如此)。

非常感谢您的任何指点。

【问题讨论】:

标签: django django-queryset


【解决方案1】:

@jma - 我假设 - 对于框 B,有多少事件处于打开状态?您提到用户处于打开状态?但是 state/event_type(Open,Closed) 与事件模型相关联。

  box = Box.objects.get(name='B') --- assuming you have a name field in Box entity

   events = Events.objects.filter(box=box,event_type='open') #queryset
   for event in events:
       #your logic here
       print(event)

3.对于盒子B和用户U,这个盒子最近打开还是关闭的事件? 假设与该用户 U 的框 B 可以有多个事件

  box = Box.objects.get(name='B') --- assuming you have a name field in Box entity
    user = User.objects.get(username='U') -- you can filter based on any field. 

此外,这取决于您要在何处实现此功能。如果您使用的是 Django 视图,那么您不需要在数据库中查询用户对象。由于请求对象具有用户属性。

In django view, user = request.user
    events = Events.objects.filter(box=box,user=user)
    for event in events:
         status = event.event_type
         if status=='Open':
              #do something
         elif status=='Closed':
              #do something
         else:
              #logic here

另外,只是一个建议

  1. 型号名称应为单数。活动
  2. 如果您只是简单地命名 event_type 字段类型而不是 event_type,那就更好了。我们已经在 Event 模型中了。因此,我们不需要通过将模型名称标记为前缀来命名字段。但是,我会远离命名字段类型。我更喜欢类别或其他东西。与 event_timestamp 相同。您可以将此字段显式命名为 to_be_held_on 或 created_at(根据您的用例)

【讨论】:

  • 一个用户可以多次改变状态:打开、关闭、打开。
  • @jma- 模型定义中的状态与事件相关联。不是用户
  • 每个事件都是关于一个(用户,盒子)(在某个时间)。用户 U1 开箱 B1 不同于 U1 开 B2 或 U2 开 B1。
  • 如果有一百个盒子,我可能希望避免 100 次服务器往返来呈现盒子计数表。
猜你喜欢
  • 1970-01-01
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
相关资源
最近更新 更多