Django ORM两个日期之间的交集

3

我有一个模型,像这样:

class Model(models.Model):
    name = models.CharField(max_length=255)
    start_date = models.DateField()
    end_date = models.DateField()
    user = models.ForeignKey(User)

在数据库中它看起来像这样:

name    start_date    end_date       user
 1      2016-01-20    2016-01-26       1
 1      2016-01-24    2016-02-02       2
 1      2016-01-28    2016-02-10       3
 2      2016-01-19    2016-01-27       4

我需要寻找在同一时间和地点生活的用户。例如,在下面的表格中,用户“2”将在名称为“1”的地方居住,并可以遇到用户“1”和用户“3”。 用户“1”只能遇到用户“2”。 “3” - 仅用户“2”。
您能告诉我如何在Django ORM中为此情况制定查询吗? 更新:
class User(models.Model):
    name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

如果您发送“class User(models.Model)”将会更好,因为您需要的东西并不明显(至少对我来说)。 - P3zhman
用户模型只有像名字(first_name)和姓氏(last_name)这样的字段,这不是很重要。 - Nikitka
你在问题中提到的"地方"指的是哪里? 是数据库中的"name"列吗? 如果是的话,用户2与用户1和3拥有相同的地方(名称为1的地方),对于用户1也一样(user 1的地方名字是"1"), 所以用户1也与用户2和用户3有共同之处。但是你提到只有用户1能够见到用户2! - P3zhman
是的,位置是“姓名”列。用户3与用户1具有不同的日期范围,所以他们不能相遇。 - Nikitka
我会有一个名为User.get_neighbours()的方法,它必须返回来自表“Model”的行。 - Nikitka
2个回答

1

检查两个人是否在同一时间、同一地点的一种方法是使用日期,并验证在该日期上具有相同位置的用户:

import datetime

date_wanted = datetime.datetime.today()
neighbour_users = User.objects.values('model_set__name').annotate(Q(start_date__lte = date_wanted) & Q(end_date__gte = date_wanted))

我认为也可以使用filter而不是annotate:
neighbour_users = User.objects.values('model_set__name').filter(start_date__lte = date_wanted, end_date__gte = date_wanted)

所以,使用values我们将用户分组在同一位置,然后通过日期进行过滤以获得所需的结果。

这并没有回答问题。它只是提供了在特定日期在某个地方的用户信息。 - nima
@nima 我认为你错了:它只会在给定日期的同一地点给出用户。请参阅文档中的values()values('model_set__name')仅对具有相同name字段值的Model行进行分组。 - doru
这很有趣,但我将在用户表中有几行,并且我想获取与其他用户的所有交集位置和日期。 - Nikitka

-1

我不确定这个能否在一个查询中完成,但是以下是我在代码中的实现方式。即使可以用一个查询完成,那也会是一个难以阅读的查询。你可以使用相同的逻辑来获取单个用户的邻居。

neighbors = []
models = Model.objects.all()
for m1 in models:
    for m2 in models:
        if m1.user_id != m2.user_id and \
            m1.name == m2.name and # if name represents the place
            ((m1.start_date >= m2.start_date and m1.start_date <= m2.end_date) or \
            (m2.start_date >= m1.start_date and m2.start_date <= m1.end_date)):
            neighbors.append((m1.name, m1.user, m2.user))

也许你的代码能够工作,但我认为它的决策速度较慢。我想在数据库中完成它。 - Nikitka
如果您创建一个包含每个日期的新表,而不是首尾日期,那么这可能更容易解决。可以通过姓名和日期匹配进行自连接来检查此表。 - joel goldstick
@joelgoldstick 是的,在这种情况下,那将简化查询,但我认为在其他情况下会使事情复杂化。此外,创建这个表并保留旧表可能会导致不一致性。 - nima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接