【问题标题】:Django filter by date range and if no records in a date, return dummy records in that without being dead in loopDjango按日期范围过滤,如果日期中没有记录,则返回其中的虚拟记录,而不会死在循环中
【发布时间】:2026-01-15 04:35:01
【问题描述】:

我有一个非常独特的需求,我在 Django 文档中没有注意到这样的解决方案。

另外,我不想在数据库查询之后使用任何loop,即使我可以在所有记录上使用loop 实现这样的解决方案。

class Example(models.Model):
    date = DateField
    name = CharField

假设我在表中有以下记录

[
 {date: "2018-01-05", name="jhon doe"},
 {date: "2018-01-11", name="jonathan someone"},
 {date: "2018-01-21", name="someone developer"},
]

和我的查询:

Example.objects.filter(date_range=["2018-01-01", "2018-01-31"])

正常情况下,当我们使用日期范围进行查询时,它会返回该范围内的所有记录。这是意料之中的正常现象。

但我希望它在某个日期范围内没有记录时带有空白记录。

我们注意到我在该范围内只有 3 条记录,所以我期待这样的结果

[
 {date: "2018-01-01", name="Not Found"},
 {date: "2018-01-02", name="Not Found"},
 {date: "2018-01-03", name="Not Found"},
 {date: "2018-01-04", name="Not Found"},
 {date: "2018-01-05", name="jhon doe"},
 {date: "2018-01-06", name="Not found"},
 '''''to be continued in a range''''
]

有没有人知道在过滤期间准备像上面这样的查询集?我需要它,因为我在前端使用了一个 javascript 工具,它需要这样的数据。

尽管我可以通过前端在前端编写实用程序函数或循环遍历所有查询集并以上述方式准备日期来实现这一点。

除了陷入循环之外,有没有人有解决办法?

感谢您的建设性回答

【问题讨论】:

  • 我不明白这可能吗?因为您的数据库中不存在不在该日期范围内的其他记录。因此,您必须创建新记录,但不要将它们保存在数据库中。然后您应该编写查询以获取所需格式的值。
  • Try this method of lte and gte 并检查 QS.count() 方法是否为零,使用普通 python 查询返回输出。

标签: django django-rest-framework django-filter


【解决方案1】:

我已经发表评论说这是不可能的,当然这取决于我的知识,但我想解释为什么以及如何解决这个问题。

假设您的 Example 模型类包含这 3 条记录。当您进行此查询时; Example.objects.filter(date_range=["2018-01-01", "2018-01-31"]) 它会像你说的那样将这些记录带到那个范围内,但是它无法获取像

这样的记录
{date: "2018-01-01", name="Not Found"},
{date: "2018-01-02", name="Not Found"}...

因为这些对象实际上并不存在于您的数据库中。我认为您必须使用循环来创建那些不在数据库中的记录。可以这样做:

# Initialize your start and end date
date_start = datetime.date(2018, 1, 1)
date_end = datetime.date(2018, 1, 31)

# Get only the dates so that we can find what is not in that range
example_dates = Example.objects.values_list('date', flat=True) 

# Initialize new list that will include records does not exists
not_found_dates = []

# Loop through in date range and if date does not exists 
# Create a dict and add it to your list
for i in range(1, (date_start - date_end).days + 1):
    new_date = date_start + datetime.timedelta(days=i)
    if new_date not in dates:
        not_found_dates.append({'date': new_date, 'name': 'Not Found'}) 

# Get your original queryset
examples = Example.objects.filter(date__range=(date_start, date_end)).values('date', 'name')
# Convert it to a list
examples = list(examples)
# Than extends examples with other list
examples.extend(example_dates)

如果您想使用您的序列化程序来转换您的查询集,而不是创建字典作为记录,您应该创建像 example=Example.objects.create(**kwargs) 这样的对象并合并 2 个查询集,以便您的序列化程序可以操作它。但这会在您的数据库中创建新记录,因此它也可能不是一个好方法。

【讨论】:

  • 是的,创建新记录是不好的做法。所以我认为我必须以任何方式使用 for 循环
  • 好像是这样。希望这有助于/解决您的问题。
  • 我其实很担心性能,因为 db 中有很多数据。然而,在我发布它之前,我也是这么想的。所以我不得不接受你的回答。感谢您的回复
  • 是的,这是一个 O(nk) 操作,但我找不到更好的解决方案。我唯一能想到的是,如果您的日期是唯一的而不是转换为列表,您可以将其转换为具有 O(1) 成员操作时间复杂度的字典,因此此代码将在 O(n) 中执行这还不错。除此之外,也许您可​​以尝试使用原始 sql 获取查询集。我认为它可以稍微改善执行时间。