Django:如何更改 AdminTimeWidget 的选择

发布于 2024-11-03 06:22:18 字数 142 浏览 5 评论 0原文

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

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

The AdminTimeWidget rendered in admin for a DateTimeField displays an icon of a clock and when you click you have the choice between: "Now Midnight 6:00 Noon".

How can I change these choices to "16h 17h 18h"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

我三岁 2024-11-10 06:22:18

克里斯有一个很好的答案。作为替代方案,您可以仅使用 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);

Chris has a great answer. As an alternative you could do this using just javascript. Place the following javascript on the pages where you want the different time options.

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);
鼻尖触碰 2024-11-10 06:22:18

子类 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 即可。

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

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

Subclass AdminTimeWidget to include a modified DateTimeShortcuts.js (get to that in a sec), then subclass AdminSplitDateTime to include your subclassed MyAdminTimeWidget instead of the default Django one:

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)

The secret sauce is in django/contrib/admin/media/js/admin/DateTimeShortcuts.js. This is what creates the list you want to modify. Copy this file and paste it into your project's site_media/js/admin directory. The relevant code you need to modify is on lines 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 + "'));");

Simply add to/delete from/modify that bit of javascript to your heart's content.

Finally, attach your new widget to any DateTimeFields you like. Your best bet for that will probably be the formfield_overrides attribute on ModelAdmin:

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.DateTimeField: {'widget': MyAdminSplitDateTime},
    }
孤独岁月 2024-11-10 06:22:18

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

这就是我所做的。

在我的 ModelAdmin 部分中,我添加了:

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 文件)。

I tried using this method and found the above javascript didn't work when multiple datetime's were present on the form.

here is what I did.

In my ModelAdmin section i added:

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

then in the js file:

$('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);
});

Note: i had to put inside a document.ready because i found that i couldn't control where the script was included in the page (seems to have be loaded before the default calendar js files).

¢好甜 2024-11-10 06:22:18

有更好的解决方案。阅读 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',
        ]

There's better solution. After reading DateTimeShortcuts.js the can be simplified to:

(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);

Then add this code to the javascript file in 'static//time-shortcuts.js' and add Meta to your admin model:

from django.contrib import admin
from .models import MyModel

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    class Media:
        js = [
            '<myapp>/time-shortcuts.js',
        ]
一袭水袖舞倾城 2024-11-10 06:22:18

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

class Class(Model):
程序=ForeignKey('程序')
当日时间 = TimeField(选择=(
(datetime.datetime.strptime('7:00 am', "%I:%M %p").time(), '7:00 am'),
(datetime.datetime.strptime('上午 8:00', "%I:%M %p").time(), '上午 8:00'),
(datetime.datetime.strptime('上午 9:00', "%I:%M %p").time(), '上午 9:00'),
(datetime.datetime.strptime('下午 6:00', "%I:%M %p").time(), '下午 6:00'),
(datetime.datetime.strptime('晚上 7:00', "%I:%M %p").time(), '晚上 7:00'),
(datetime.datetime.strptime('晚上 8:00', "%I:%M %p").time(), '晚上 8:00'),
(datetime.datetime.strptime('晚上 9:00', "%I:%M %p").time(), '晚上 9:00'),
))

希望这有帮助

I went with a much simpler approach and it worked for me. I simply added choices to my model using the following code:

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'),
))

Hope this helps

为你鎻心 2024-11-10 06:22:18

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

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

/static/admin/js/ 中管理/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 + "'));");
}

Overriding JS by DateTimeShortcuts.overrideTimeOptions function works only with one form
( bug: the change of time in child model affects parent model, so you can't change timefield in child model form by this widget)

If you want use custom time options with inlines:

in /static/admin/js/admin/DateTimeShortcuts.js
replace:

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 + "'));");

by:

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 + "'));");
}
半步萧音过轻尘 2024-11-10 06:22:18

扩展@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())

Expanding on @Bit68's answer, assuming other folks might want to create lists of regularly spaced times more than once, I created a helper function to build a choices tuple. (I'm adding a new answer because this length of code is too hard to follow in a comment.) This works in Django 2.2.

Note that this creates a dropdown list of options, it doesn't add options to the default admin date/time widget as the javascript methods do.

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

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

〃安静 2024-11-10 06:22:18

在检查了 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);
});

After checking the source code of DateTimeShortcuts.js I found quite easy to overwrite the function that handles DateTimeShortcuts.clockHours.default_ and make it manage also floats like 16.5 (for "16:30"). I can now do much more, like synchronizing two time inputs (as I have two start_at and end_at fields):

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);
});
你的笑 2024-11-10 06:22:18

谢谢大家在这里提供的一些好建议。我得到了这个简单的解决方案。我将这个 admin.js 文件放在 project/static/admin.js 中。该文件的内容是:

$(function () {
    DateTimeShortcuts.clockHours.default_ = [
        ['Now', -1], ['Midnight', 0], ['Market Open', 9], ['Market Close', 16]]
});

然后在 admin.py 中我有这个:

@admin.register(Trade)
class TradeAdmin(admin.ModelAdmin):
     ...
     class Media:
         js = ('/static/admin.js',)

现在,我在交易模型管理中的数据时间字段的小时钟小部件有以下选择:现在、午夜、市场开盘和市场收盘。

Thank you all for some good tips here. I got this simple solution working. I put this admin.js file in project/static/admin.js. The contents of that file are:

$(function () {
    DateTimeShortcuts.clockHours.default_ = [
        ['Now', -1], ['Midnight', 0], ['Market Open', 9], ['Market Close', 16]]
});

Then in admin.py I have this:

@admin.register(Trade)
class TradeAdmin(admin.ModelAdmin):
     ...
     class Media:
         js = ('/static/admin.js',)

And now my little clock widget for my data time field in the Trade model admin has these choices: Now, Midnight, Market Open, and Market Close.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文