Django:如何更改 AdminTimeWidget 的选择

问题描述 投票:0回答:8

在管理中为

AdminTimeWidget
呈现的
DateTimeField
显示一个时钟图标,当您单击时,您可以选择:“现在午夜 6:00 中午”。

如何将这些选项更改为“16h 17h 18h”?

django django-admin django-forms
8个回答
14
投票

克里斯有一个很好的答案。作为替代方案,您可以仅使用 javascript 来完成此操作。将以下 javascript 放置在您想要不同时间选项的页面上。

DateTimeShortcuts.overrideTimeOptions = function () {
    // Find the first time element
    timeElement = django.jQuery("ul.timelist li").eq(0).clone();
    originalHref = timeElement.find('a').attr('href');

    // remove all existing time elements
    django.jQuery("ul.timelist li").remove();

    // add new time elements representing those you want
    var i=0;
    for (i=0;i<=23;i++) {
        // use a regular expression to update the link
        newHref = originalHref.replace(/Date\([^\)]*\)/g, "Date(1970,1,1," + i + ",0,0,0)");
        // update the text for the element
        timeElement.find('a').attr('href', newHref).text(i+"h");
        // Add the new element into the document
        django.jQuery("ul.timelist").append(timeElement.clone());
    }
}

addEvent(window, 'load', DateTimeShortcuts.overrideTimeOptions);

10
投票

子类

AdminTimeWidget
以包含修改后的 DateTimeShortcuts.js (一秒钟即可完成),然后子类
AdminSplitDateTime
以包含您的子类
MyAdminTimeWidget
而不是默认的 Django 子类:

from django.contrib.admin.widgets import AdminTimeWidget
from django.conf import settings

class MyAdminTimeWidget(AdminTimeWidget):
    class Media:
        js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
              settings.MEDIA_URL + "js/admin/DateTimeShortcuts.js")

class MyAdminSplitDateTime(AdminSplitDateTime):
    def __init__(self, attrs=None):
        widgets = [AdminDateWidget, MyAdminTimeWidget]
        forms.MultiWidget.__init__(self, widgets, attrs)

秘密酱汁在

django/contrib/admin/media/js/admin/DateTimeShortcuts.js
。这就是创建您要修改的列表的原因。复制此文件并将其粘贴到项目的
site_media/js/admin
目录中。您需要修改的相关代码在第85-88行:

quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");

只需根据您的喜好添加/删除/修改那段 javascript 即可。

最后,将新小部件附加到您喜欢的任何日期时间字段。您最好的选择可能是

formfield_overrides
上的
ModelAdmin
属性:

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.DateTimeField: {'widget': MyAdminSplitDateTime},
    }

5
投票

我尝试使用此方法,发现当表单上存在多个日期时间时,上述 JavaScript 不起作用。

这就是我所做的。

在我的模型管理部分我添加了:

class Media:
    js = ('js/clock_time_selections.js',)

然后在js文件中:

$('document').ready(function () {
    DateTimeShortcuts.overrideTimeOptions = function () {
        var clockCount = 0;
        console.log('ready');
        $('ul.timelist').each(function () {
            var $this = $(this);
            var originalHref = $this.find('a').attr('href');
            console.log(originalHref);
            $this.find('li').remove();
            for (i=8; i <= 20; i++) {
                var newLink = '<li><a href="javascript:DateTimeShortcuts.handleClockQuicklink('+ clockCount + ', ' + i
                    + ');"> ' + i + ':00h</a></li>';
                $this.append(newLink);
            }
            //console.log($this.html());

            clockCount++;
        });
    };

    addEvent(window, 'load', DateTimeShortcuts.overrideTimeOptions);
});

注意:我必须放入 document.ready 中,因为我发现我无法控制脚本包含在页面中的位置(似乎已在默认日历 js 文件之前加载)。


4
投票

有更好的解决方案。阅读完DateTimeShortcuts.js后,可以简化为:

(function ($) {
    $(document).ready(function () {

        DateTimeShortcuts.clockHours.default_ = [];

        for (let hour = 8; hour <= 20; hour++) {
            let verbose_name = new Date(1970, 1, 1, hour, 0, 0).strftime('%H:%M');
            DateTimeShortcuts.clockHours.default_.push([verbose_name, hour])
        }

    });
})(django.jQuery);

然后将此代码添加到“static//time-shortcuts.js”中的 javascript 文件中,并将 Meta 添加到您的管理模型中:

from django.contrib import admin
from .models import MyModel

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    class Media:
        js = [
            '<myapp>/time-shortcuts.js',
        ]

3
投票

我采用了一种更简单的方法,它对我有用。我只是使用以下代码向我的模型添加了选择:

class Class(Model):
    program = ForeignKey('Program')
    time_of_the_day = TimeField(choices=(
        (datetime.datetime.strptime('7:00 am', "%I:%M %p").time(), '7:00 am'),
        (datetime.datetime.strptime('8:00 am', "%I:%M %p").time(), '8:00 am'),
        (datetime.datetime.strptime('9:00 am', "%I:%M %p").time(), '9:00 am'),
        (datetime.datetime.strptime('6:00 pm', "%I:%M %p").time(), '6:00 pm'),
        (datetime.datetime.strptime('7:00 pm', "%I:%M %p").time(), '7:00 pm'),
        (datetime.datetime.strptime('8:00 pm', "%I:%M %p").time(), '8:00 pm'),
        (datetime.datetime.strptime('9:00 pm', "%I:%M %p").time(), '9:00 pm'),
))

希望这有帮助


1
投票

通过 DateTimeShortcuts.overrideTimeOptions 函数覆盖 JS 仅适用于一种表单 (错误:子模型中时间的更改会影响父模型,因此您无法通过此小部件更改子模型表单中的时间字段)

如果您想使用带有内联的自定义时间选项:

/static/admin/js/admin/DateTimeShortcuts.js 替换:

quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href",    "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");

作者:

for(j=6;j<=23;j++){
    quickElement("a", quickElement("li", time_list, ""), j+":00", "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1," + j + ",0,0,0).strftime('" + time_format + "'));");
}

0
投票

扩展@Bit68的答案,假设其他人可能想要多次创建规则间隔时间的列表,我创建了一个辅助函数来构建选择元组。 (我添加了一个新答案,因为这段代码太难在注释中遵循。)这适用于 Django 2.2。

请注意,这会创建一个选项下拉列表,它不会像 javascript 方法那样将选项添加到默认管理日期/时间小部件。

import datetime

def get_time_choices(start_time=datetime.time(9,0,0), end_time=datetime.time(17,0,0), delta=datetime.timedelta(minutes=15)):
    '''
        Builds a choices tuple of (time object, time string) tuples
        starting at the start time specified and ending at or before 
        the end time specified in increments of size delta.

        The default is to return a choices tuple for 
        9am to 5pm in 15-minute increments.
    '''
    time_choices = ()
    time = start_time
    while time <= end_time:
        time_choices += ((time, time.strftime("%I:%M %p")),)
        # This complicated line is because you can't add
        # a timedelta object to a time object.
        time = (datetime.datetime.combine(datetime.date.today(), time) + delta).time()
    return time_choices

然后

time_of_the_day = models.TimeField(choices=get_time_choices())


0
投票

检查了 DateTimeShortcuts.js 的源代码后,我发现很容易覆盖处理

DateTimeShortcuts.clockHours.default_
的函数并使其管理像
16.5
一样的浮动(对于“16:30”)。我现在可以做更多事情,例如同步两个时间输入(因为我有两个 start_at 和 end_at 字段):

window.addEventListener('load', function () {
    (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);
        };
    })(django.jQuery);
});
© www.soinside.com 2019 - 2024. All rights reserved.