Django: how to change the choices of AdminTimeWidget

后端 未结 6 1766
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-08 12:29

The AdminTimeWidget rendered in admin for a DateTimeField displays an icon of a clock and when you click you have the choice between: \"Now Midnigh

相关标签:
6条回答
  • 2020-12-08 12:33

    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

    0 讨论(0)
  • 2020-12-08 12:38

    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',
            ]
    
    0 讨论(0)
  • 2020-12-08 12:43

    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},
        }
    
    0 讨论(0)
  • 2020-12-08 12:45

    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);
    
    0 讨论(0)
  • 2020-12-08 12:48

    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).

    0 讨论(0)
  • 2020-12-08 12:54

    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 + "'));");
    }
    
    0 讨论(0)
提交回复
热议问题