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

如何在Django模型中自定义字段存储商家一周每日营业时间

Django自定义营业时间字段实现方案

方案1:基于JSONField封装轻量实现(推荐)

该方案复用Django内置JSONField,仅需补充营业时间格式校验逻辑即可满足需求,无需完全重写字段核心逻辑,开发和维护成本最低。

兼容所有支持JSON字段的数据库(MySQL 5.7+、PostgreSQL、SQLite 3.9+等)
首先定义营业时间格式验证器:

from django.core.exceptions import ValidationError
import datetime

def validate_opening_hours(value):
    # 约定格式:键为1-7对应周一到周日,值为时段列表,每个时段包含open/close两个HH:MM格式的时间
    if not isinstance(value, dict):
        raise ValidationError("营业时间必须为对象格式")
    # 校验必须包含7天的配置
    for day in map(str, range(1, 8)):
        if day not in value:
            raise ValidationError(f"缺少周{day}的营业时间配置")
        if not isinstance(value[day], list):
            raise ValidationError(f"周{day}的营业时间必须为时段列表")
        # 校验每个时段的时间格式
        for period in value[day]:
            if "open" not in period or "close" not in period:
                raise ValidationError(f"周{day}时段缺少开门/关门时间")
            for time_key in ["open", "close"]:
                try:
                    datetime.datetime.strptime(period[time_key], "%H:%M")
                except ValueError:
                    raise ValidationError(f"时间格式错误,必须为HH:MM格式")

在Restaurant模型中添加字段即可:

class Restaurant(models.Model):
    # 原有字段保持不变
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30)
    city = models.CharField(max_length=15)
    street = models.CharField(max_length=15)
    house_number = models.CharField(max_length=3)
    flat_number = models.CharField(max_length=3, default='0')
    phone_number = models.CharField(max_length=12)
    image = models.ImageField()
    rating = models.FloatField(validators=[validate_rating_number])
    # 新增营业时间字段
    opening_hours = models.JSONField(
        default=dict,
        validators=[validate_opening_hours],
        help_text="格式:键为1-7代表周一到周日,值为时段列表,每个时段包含open和close时间,格式为HH:MM"
    )

    def __str__(self):
        return f'{self.name}, {self.city}'

方案2:完全自定义独立字段类(符合要求的models.CustomField调用形式)

如果需要封装成独立的字段类型复用,可以继承Django的Field基类实现完整的自定义字段:

from django.db import models
from django.core.exceptions import ValidationError
import json
import datetime

# 复用方案1的验证器
def validate_opening_hours(value):
    if not isinstance(value, dict):
        raise ValidationError("营业时间必须为对象格式")
    for day in map(str, range(1, 8)):
        if day not in value:
            raise ValidationError(f"缺少周{day}的营业时间配置")
        if not isinstance(value[day], list):
            raise ValidationError(f"周{day}的营业时间必须为时段列表")
        for period in value[day]:
            if "open" not in period or "close" not in period:
                raise ValidationError(f"周{day}时段缺少开门/关门时间")
            for time_key in ["open", "close"]:
                try:
                    datetime.datetime.strptime(period[time_key], "%H:%M")
                except ValueError:
                    raise ValidationError(f"时间格式错误,必须为HH:MM格式")

class OpeningHoursField(models.Field):
    description = "存储一周7天的营业时间"

    def __init__(self, *args, **kwargs):
        kwargs['default'] = dict
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        return name, path, args, kwargs

    def from_db_value(self, value, expression, connection):
        # 从数据库读取时转为Python字典
        if value is None:
            return {}
        return json.loads(value)

    def to_python(self, value):
        # 反序列化为Python对象
        if isinstance(value, dict):
            return value
        try:
            return json.loads(value)
        except (TypeError, ValueError):
            raise ValidationError("无效的营业时间格式")

    def get_prep_value(self, value):
        # 存入数据库前转为JSON字符串
        validate_opening_hours(value)
        return json.dumps(value)

    def db_type(self, connection):
        # 数据库层存储为JSON类型
        return 'json'

在模型中直接调用即可:

opening_hours = OpeningHoursField()

用法示例

# 赋值
restaurant = Restaurant.objects.create(
    # 其他字段赋值省略
    opening_hours = {
        "1": [{"open": "09:00", "close": "22:00"}],
        "2": [{"open": "09:00", "close": "22:00"}],
        "3": [{"open": "09:00", "close": "22:00"}],
        "4": [{"open": "09:00", "close": "22:00"}],
        "5": [{"open": "09:00", "close": "23:00"}],
        "6": [{"open": "10:00", "close": "23:00"}],
        "7": [{"open": "10:00", "close": "22:00"}],
    }
)
# 访问周六营业时间
print(restaurant.opening_hours["6"])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:57:02