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

重写DateTimeShortcuts扩展AdminTimeWidget时遇未定义错误求助

问题描述

尝试通过重写DateTimeShortcuts为AdminTimeWidget添加更多时间选项,但控制台抛出以下错误:

  • Uncaught ReferenceError: DateTimeShortcuts is not defined
  • jQuery.Deferred exception: DateTimeShortcuts is not defined ReferenceError: DateTimeShortcuts is not defined at HTMLDocument

相关实现代码如下:

自定义JS文件

(function($) {
    $(document).ready(function() {
        DateTimeShortcuts.clockHours.default_ = [
            ['16:30', 16.5],
            ['17:30', 17.5],
            ['18:00', 18],
            ['19:00', 19],
            ['20:00', 20],
        ];

        DateTimeShortcuts.handleClockQuicklink = function (num, val) {
            let d;
            if (val == -1) {
                d = DateTimeShortcuts.now();
            } else {
                const h = val | 0;
                const m = (val - h) * 60;
                d = new Date(1970, 1, 1, h, m, 0, 0);
            }
            DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);
            DateTimeShortcuts.clockInputs[num].focus();
            DateTimeShortcuts.dismissClock(num);
        };
    });
})(jQuery);

ModelAdmin配置

@admin.register(models.MyModel)
class MyAdminModel():
   # 其他配置
   list_filter = [("created", custom_titled_datetime_range_filter("By created"))]

   class Media:
        js = ("admin/js/DateTimeShortcuts.js",)

自定义日期范围过滤器

def custom_titled_datetime_range_filter(title):
    class CustomDateTimeRangeFilter(DateTimeRangeFilter):
        def __init__(self, field, request, params, model, model_admin, field_path):
            super().__init__(field, request, params, model, model_admin, field_path)
            self.title = title

    return CustomDateTimeRangeFilter
错误原因及解决方案

1. ModelAdmin未继承基类

你的MyAdminModel没有继承admin.ModelAdmin,导致Media类无法被Django Admin正确识别加载,直接影响JS文件的引入逻辑。

修改ModelAdmin定义:

@admin.register(models.MyModel)
class MyAdminModel(admin.ModelAdmin):  # 补充继承基类
   # 其他配置
   list_filter = [("created", custom_titled_datetime_range_filter("By created"))]

   class Media:
        # 先加载Django自带的DateTimeShortcuts,再加载自定义JS(替换为你的自定义JS实际路径)
        js = (
            "admin/js/DateTimeShortcuts.js",
            "admin/js/custom_datetime_shortcuts.js",
        )

2. JS加载顺序错误

自定义JS依赖DateTimeShortcuts对象,必须确保Django自带的DateTimeShortcuts.js先加载完成,再执行你的自定义代码。如果顺序颠倒,就会出现对象未定义的错误。

注意:不同Django版本的DateTimeShortcuts.js路径有差异:

  • Django 2.x及更早:admin/js/DateTimeShortcuts.js
  • Django 3.x+:admin/js/django/DateTimeShortcuts.js
    请根据你的Django版本调整路径。

3. 增加加载检查(可选)

如果调整顺序后仍有问题,可以在自定义JS中增加存在性检查,确保DateTimeShortcuts加载完成后再执行修改逻辑:

(function($) {
    function waitForDateTimeShortcuts() {
        if (typeof DateTimeShortcuts !== 'undefined') {
            DateTimeShortcuts.clockHours.default_ = [
                ['16:30', 16.5],
                ['17:30', 17.5],
                ['18:00', 18],
                ['19:00', 19],
                ['20:00', 20],
            ];

            DateTimeShortcuts.handleClockQuicklink = function (num, val) {
                let d;
                if (val == -1) {
                    d = DateTimeShortcuts.now();
                } else {
                    const h = val | 0;
                    const m = (val - h) * 60;
                    d = new Date(1970, 1, 1, h, m, 0, 0);
                }
                DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);
                DateTimeShortcuts.clockInputs[num].focus();
                DateTimeShortcuts.dismissClock(num);
            };
        } else {
            setTimeout(waitForDateTimeShortcuts, 100);
        }
    }

    $(document).ready(function() {
        waitForDateTimeShortcuts();
    });
})(jQuery);

4. 版本兼容替代方案(高版本Django)

部分新版本Django对Admin JS结构做了调整,直接修改DateTimeShortcuts可能失效。此时建议通过自定义AdminTimeWidget实现需求:

from django.contrib.admin.widgets import AdminTimeWidget

class CustomAdminTimeWidget(AdminTimeWidget):
    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        # 传递自定义时间选项到模板
        context['custom_time_choices'] = [
            ('16:30', '16:30'),
            ('17:30', '17:30'),
            ('18:00', '18:00'),
            ('19:00', '19:00'),
            ('20:00', '20:00'),
        ]
        return context

# 在ModelAdmin中使用自定义Widget
@admin.register(models.MyModel)
class MyAdminModel(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name == 'your_time_field':  # 替换为你的时间字段名
            kwargs['widget'] = CustomAdminTimeWidget
        return super().formfield_for_dbfield(db_field, **kwargs)

之后复制Django自带的admin/widgets/time.html模板,添加自定义时间选项的渲染逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:23:19