You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中JSONField存营业时间及查询营业商家的方案咨询

解决方案

一、基于现有JSONField的查询实现

1. 数据库层面查询(仅PostgreSQL)

如果你的Django项目使用PostgreSQL作为数据库,可以利用jsonb的原生查询能力直接在数据库层面完成过滤,性能更优:

假设商家模型为Merchant,营业时间字段是opening_hours(JSONField类型)。要查询**周一(索引0)、用户时间为"8:00"**的营业商家,代码如下:

from django.db.models import Q, Func, Value

# 格式化用户时间为HH:MM格式字符串
user_time = "8:00"

# 构造查询条件
open_merchants = Merchant.objects.filter(
    # 指定日期索引的closed为false
    Q(opening_hours__0__closed=False) &
    # 检查该日期下存在有效时间段,且用户时间落在其中
    Func(
        Value(user_time),
        function="jsonb_path_exists",
        template="%(function)s(opening_hours->%(expressions)s, '$[*] ? (@[0] != \"\" && @[1] != \"\" && @[0] <= $time && @[1] >= $time)')",
        time=user_time
    )
)

2. Python层面过滤(兼容所有数据库)

如果使用SQLite或其他对JSON查询支持有限的数据库,可以先拉取候选商家,再在Python中完成过滤逻辑:

from datetime import time

def check_is_open(merchant, day_index, user_time_str):
    # 解析用户时间为time对象
    try:
        hours, minutes = map(int, user_time_str.split(":"))
        user_time = time(hours, minutes)
    except ValueError:
        return False
    
    # 获取对应日期的营业配置
    if day_index >= len(merchant.opening_hours):
        return False
    day_config = merchant.opening_hours[day_index]
    if day_config.get("closed"):
        return False
    
    # 遍历所有时间段检查
    for slot in day_config.get("times", []):
        start_str, end_str = slot
        if not start_str or not end_str:
            continue
        try:
            start_h, start_m = map(int, start_str.split(":"))
            end_h, end_m = map(int, end_str.split(":"))
            start_time = time(start_h, start_m)
            end_time = time(end_h, end_m)
        except ValueError:
            continue
        
        if start_time <= user_time <= end_time:
            return True
    return False

# 使用示例:筛选周一(索引0)、用户时间"8:00"的营业商家
day_index = 0
user_time = "8:00"
all_merchants = Merchant.objects.all()
open_merchants = [m for m in all_merchants if check_is_open(m, day_index, user_time)]

二、更优的营业时间存储方案

JSONField虽然灵活,但存在查询效率低、数据约束弱、维护成本高的问题,推荐采用关系型数据库规范化设计:

1. 模型设计

from django.db import models

class Merchant(models.Model):
    name = models.CharField(max_length=255)
    # 商家其他字段...

class BusinessHours(models.Model):
    DAY_CHOICES = [
        (0, "周一"),
        (1, "周二"),
        (2, "周三"),
        (3, "周四"),
        (4, "周五"),
        (5, "周六"),
        (6, "周日"),
    ]
    merchant = models.ForeignKey(Merchant, on_delete=models.CASCADE, related_name="business_hours")
    day_of_week = models.IntegerField(choices=DAY_CHOICES)
    is_closed = models.BooleanField(default=False)

    class Meta:
        unique_together = ("merchant", "day_of_week")  # 保证每个商家每天仅一条配置

class TimeSlot(models.Model):
    business_hour = models.ForeignKey(BusinessHours, on_delete=models.CASCADE, related_name="time_slots")
    start_time = models.TimeField()
    end_time = models.TimeField()

2. 核心优势

  • 查询高效:通过字段直接过滤,可创建索引大幅提升查询速度
  • 数据合规:利用TimeField保证时间格式合法,避免JSON中的无效值
  • 易于维护:修改营业时间无需操作复杂JSON结构,直接操作模型实例即可

3. 对应查询示例

查询周一(day_of_week=0)、用户时间为8:00的营业商家:

from datetime import time

user_time = time(8, 0)
open_merchants = Merchant.objects.filter(
    business_hours__day_of_week=0,
    business_hours__is_closed=False,
    business_hours__time_slots__start_time__lte=user_time,
    business_hours__time_slots__end_time__gte=user_time
).distinct()

内容的提问来源于stack exchange,提问作者PietroPutelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:55:33