关于python:以自定义形式使用Django时间/日期小部件

Using Django time/date widgets in custom form

如何在自定义视图中使用默认管理员使用的漂亮的JavaScript日期和时间小部件?

我浏览了Django表单文档,其中简要提到了django.contrib.admin.widgets,但我不知道如何使用它?

这是我希望将其应用于的模板。

1
2
3
4
5
6
7
8
<form action="." method="POST">
    <table>
        {% for f in form %}
           <tr> <td> {{ f.name }}</td> <td>{{ f }}</td> </tr>
        {% endfor %}
    </table>
    <input type="submit" name="submit" value="Add Product">
</form>

另外,我认为应该指出的是,我并未真正为这种形式编写视图,而是使用了通用视图。 这是url.py中的条目:

1
(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

而且我对整个Django / MVC / MTV都是陌生的,所以请放轻松...


随着时间的流逝,此答案的复杂性不断提高,并且需要进行许多破解,可能应该警告您绝对不要这样做。它依赖于管理员未公开的内部实现细节,可能会在Django的未来版本中再次中断,并且比找到另一个JS日历小部件并使用它更容易实现。

就是说,如果您决心进行这项工作,这是您必须做的:

  • 为模型定义自己的ModelForm子类(最好将其放入应用程序的forms.py中),并告诉它使用AdminDateWidget / AdminTimeWidget / AdminSplitDateTime(用模型中的正确字段名称替换" mydate"等):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from django import forms
    from my_app.models import Product
    from django.contrib.admin import widgets                                      

    class ProductForm(forms.ModelForm):
        class Meta:
            model = Product
        def __init__(self, *args, **kwargs):
            super(ProductForm, self).__init__(*args, **kwargs)
            self.fields['mydate'].widget = widgets.AdminDateWidget()
            self.fields['mytime'].widget = widgets.AdminTimeWidget()
            self.fields['mydatetime'].widget = widgets.AdminSplitDateTime()
  • 更改URLconf,以将" form_class":ProductForm而不是" model":Product传递给通用的create_object视图(这当然意味着"从my_app.forms导入ProductForm"而不是"从my_app.models导入Product")。

  • 在模板的开头,包括{{form.media}},以输出指向Javascript文件的链接。

  • hacky部分:admin日期/时间小部件假定i18n JS东西已加载,并且也需要core.js,但不会自动提供其中任何一个。因此,在{{form.media}}上方的模板中,您需要:

    1
    2
    <script type="text/javascript" src="/my_admin/jsi18n/">
    <script type="text/javascript" src="/media/admin/js/core.js">

    您可能还希望使用以下管理CSS(感谢Alex提到了这一点):

    1
    2
    3
    4
    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>
  • 这意味着Django的管理媒体(ADMIN_MEDIA_PREFIX)位于/ media / admin /-您可以更改其设置。理想情况下,您将使用上下文处理器将此值传递给模板,而不是对其进行硬编码,但这超出了此问题的范围。

    这还要求将URL / my_admin / jsi18n /手动连接到django.views.i18n.javascript_catalog视图(如果不使用I18N,则为null_javascript_catalog)。您必须自己执行此操作,而不是通过admin应用程序,因此无论您是否登录管理员都可以访问它(感谢Jeremy指出了这一点)。 URLconf的示例代码:

    1
    (r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

    最后,如果您使用的是Django 1.2或更高版本,则需要在模板中添加一些其他代码来帮助小部件找到其媒体:

    1
    2
    3
    4
    5
    {% load adminmedia %} /* At the top of the template. */

    /* In the head section of the template. */
    <script type="text/javascript">
    window.__admin_media_prefix__ ="{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";

    感谢lupefiasco的添加。


    由于该解决方案有点漏洞,因此我认为将您自己的日期/时间窗口小部件与一些JavaScript结合使用更可行。


    是的,我最终覆盖了/ admin / jsi18n /网址。

    这是我在urls.py中添加的内容。确保它在/ admin /网址上方

    1
        (r'^admin/jsi18n', i18n_javascript),

    这是我创建的i18n_javascript函数。

    1
    2
    3
    from django.contrib import admin
    def i18n_javascript(request):
      return admin.site.i18n_javascript(request)

    我的1.4版头代码(有些是新增的,有些是删除的)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    {% block extrahead %}

    <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/widgets.css"/>

    <script type="text/javascript" src="/admin/jsi18n/">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/core.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.init.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/actions.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/calendar.js">
    <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/DateTimeShortcuts.js">

    {% endblock %}

    我发现自己经常引用这篇文章,并且发现文档定义了一种略微不明智的方式来覆盖默认小部件。

    (无需重写ModelForm的__init__方法)

    但是,您仍然需要如Carl所述适当地连接JS和CSS。

    forms.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from django import forms
    from my_app.models import Product
    from django.contrib.admin import widgets                                      


    class ProductForm(forms.ModelForm):
        mydate = forms.DateField(widget=widgets.AdminDateWidget)
        mytime = forms.TimeField(widget=widgets.AdminTimeWidget)
        mydatetime = forms.SplitDateTimeField(widget=widgets.AdminSplitDateTime)

        class Meta:
            model = Product

    参考字段类型以查找默认表单字段。


    从Django 1.2 RC1开始,如果您使用的是Django admin日期选择器widge技巧,则必须将以下内容添加到模板中,否则您将看到通过" / missing-admin-media-prefix"引用的日历图标url /"。

    1
    2
    3
    4
    5
    {% load adminmedia %} /* At the top of the template. */

    /* In the head section of the template. */
    <script type="text/javascript">
    window.__admin_media_prefix__ ="{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";


    为了补充Carl Meyer的答案,我想评论一下,您需要将该标头放在模板中的某个有效块中(标头内)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {% block extra_head %}

    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

    <script type="text/javascript" src="/admin/jsi18n/">
    <script type="text/javascript" src="/media/admin/js/core.js">
    <script type="text/javascript" src="/media/admin/js/admin/RelatedObjectLookups.js">

    {{ form.media }}

    {% endblock %}

    如果以上操作失败,以下内容也将作为最后的手段

    1
    2
    3
    4
    5
    6
    7
    class PaymentsForm(forms.ModelForm):
        class Meta:
            model = Payments

        def __init__(self, *args, **kwargs):
            super(PaymentsForm, self).__init__(*args, **kwargs)
            self.fields['date'].widget = SelectDateWidget()

    如同

    1
    2
    3
    4
    5
    class PaymentsForm(forms.ModelForm):
        date = forms.DateField(widget=SelectDateWidget())

        class Meta:
            model = Payments

    把它放在你的forms.py from django.forms.extras.widgets import SelectDateWidget


    对于Django> = 2.0

    Note: Using admin widgets for date-time fields is not a good idea as admin style-sheets can conflict with your site style-sheets in case you are using bootstrap or any other CSS frameworks. If you are building your site on bootstrap use my bootstrap-datepicker widget django-bootstrap-datepicker-plus.

    步骤1:将javascript-catalog URL添加到项目(而非应用程序)的urls.py文件中。

    1
    2
    3
    4
    5
    from django.views.i18n import JavaScriptCatalog

    urlpatterns = [
        path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
    ]

    步骤2:将所需的JavaScript / CSS资源添加到模板中。

    1
    2
    3
    4
    5
    <script type="text/javascript" src="{% url 'javascript-catalog' %}">
    <script type="text/javascript" src="{% static '/admin/js/core.js' %}">
    <link rel="stylesheet" type="text/css" href="{% static '/admin/css/widgets.css' %}">
    <style>.calendar>table>caption{caption-side:unset}</style><!--caption fix for bootstrap4-->
    {{ form.media }}        {# Form required JS and CSS #}

    步骤3:在forms.py中,将管理小部件用于日期时间输入字段。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from django.contrib.admin import widgets
    from .models import Product

    class ProductCreateForm(forms.ModelForm):
        class Meta:
            model = Product
            fields = ['name', 'publish_date', 'publish_time', 'publish_datetime']
            widgets = {
                'publish_date': widgets.AdminDateWidget,
                'publish_time': widgets.AdminTimeWidget,
                'publish_datetime': widgets.AdminSplitDateTime,
            }

    仅向您的窗口小部件分配一个类,然后将该类绑定到JQuery datepicker怎么样?

    Django Forms.py:

    1
    2
    3
    4
    5
    6
    7
    8
    class MyForm(forms.ModelForm):

      class Meta:
        model = MyModel

      def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['my_date_field'].widget.attrs['class'] = 'datepicker'

    以及模板的一些JavaScript:

    1
      $(".datepicker").datepicker();

    我用这个很好,但是模板有两个问题:

  • 对于模板中的每个字段,我都会两次看到日历图标。
  • 对于TimeField,我有"输入有效日期"。

    Here is a screenshot of the Form

  • models.py

    1
    2
    3
    4
    5
    from django.db import models
        name=models.CharField(max_length=100)
        create_date=models.DateField(blank=True)
        start_time=models.TimeField(blank=False)
        end_time=models.TimeField(blank=False)

    forms.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from django import forms
    from .models import Guide
    from django.contrib.admin import widgets

    class GuideForm(forms.ModelForm):
        start_time = forms.DateField(widget=widgets.AdminTimeWidget)
        end_time = forms.DateField(widget=widgets.AdminTimeWidget)
        create_date = forms.DateField(widget=widgets.AdminDateWidget)
        class Meta:
            model=Guide
            fields=['name','categorie','thumb']


    使用required = False更新了SplitDateTime的解决方案和解决方法:

    forms.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from django import forms

    class SplitDateTimeJSField(forms.SplitDateTimeField):
        def __init__(self, *args, **kwargs):
            super(SplitDateTimeJSField, self).__init__(*args, **kwargs)
            self.widget.widgets[0].attrs = {'class': 'vDateField'}
            self.widget.widgets[1].attrs = {'class': 'vTimeField'}  


    class AnyFormOrModelForm(forms.Form):
        date = forms.DateField(widget=forms.TextInput(attrs={'class':'vDateField'}))
        time = forms.TimeField(widget=forms.TextInput(attrs={'class':'vTimeField'}))
        timestamp = SplitDateTimeJSField(required=False,)

    form.html

    1
    2
    3
    4
    <script type="text/javascript" src="/admin/jsi18n/">
    <script type="text/javascript" src="/admin_media/js/core.js">
    <script type="text/javascript" src="/admin_media/js/calendar.js">
    <script type="text/javascript" src="/admin_media/js/admin/DateTimeShortcuts.js">

    urls.py

    1
    (r'^admin/jsi18n/', 'django.views.i18n.javascript_catalog'),

    我的Django设定:1.11
    引导程序:3.3.7

    由于没有一个答案是完全清楚的,因此我共享我的模板代码,该代码完全没有错误。

    模板的上半部分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {% extends 'base.html' %}
    {% load static %}
    {% load i18n %}

    {% block head %}
        Add Interview
    {% endblock %}

    {% block content %}

    <script type="text/javascript" src="{% url 'javascript-catalog' %}">
    <script type="text/javascript" src="{% static 'admin/js/core.js' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}"/>
    <link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script type="text/javascript" src="{% static 'js/jquery.js' %}">

    下半区:

    1
    2
    3
    4
    5
    <script type="text/javascript" src="/admin/jsi18n/">
    <script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.min.js' %}">
    <script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}">
    <script type="text/javascript" src="{% static 'admin/js/actions.min.js' %}">
    {% endblock %}

    在Django 10中。
    MyProject的/ urls.py:
    在urlpatterns的开头

    1
    2
    3
    4
    5
    6
    7
      from django.views.i18n import JavaScriptCatalog

    urlpatterns = [
        url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
    .
    .
    .]

    在我的template.html中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    {% load staticfiles %}

        <script src="{% static"js/jquery-2.2.3.min.js" %}">
        <script src="{% static"js/bootstrap.min.js" %}">
        {# Loading internazionalization for js #}
        {% load i18n admin_modify %}
        <script type="text/javascript" src="{% url 'javascript-catalog' %}">
        <script type="text/javascript" src="{% static"/admin/js/jquery.init.js" %}">

        <link rel="stylesheet" type="text/css" href="{% static"/admin/css/base.css" %}">
        <link rel="stylesheet" type="text/css" href="{% static"/admin/css/forms.css" %}">
        <link rel="stylesheet" type="text/css" href="{% static"/admin/css/login.css" %}">
        <link rel="stylesheet" type="text/css" href="{% static"/admin/css/widgets.css" %}">



        <script type="text/javascript" src="{% static"/admin/js/core.js" %}">
        <script type="text/javascript" src="{% static"/admin/js/SelectFilter2.js" %}">
        <script type="text/javascript" src="{% static"/admin/js/admin/RelatedObjectLookups.js" %}">
        <script type="text/javascript" src="{% static"/admin/js/actions.js" %}">
        <script type="text/javascript" src="{% static"/admin/js/calendar.js" %}">
        <script type="text/javascript" src="{% static"/admin/js/admin/DateTimeShortcuts.js" %}">


    推荐阅读

      linux默认命令删除?

      linux默认命令删除?,系统,软件,名称,档案,命令,文件,目录,不了,电脑,文件夹,

      linux命令简写自定义?

      linux命令简写自定义?,系统,状态,命令,代码,工具,发行,标准,软件,文件,别名,L

      linux切换日期命令?

      linux切换日期命令?,时间,系统,信息,命令,城市,终端,时分,日期,窗口,操作系

      linux命令默认加后缀?

      linux命令默认加后缀?,系统,文件,密码,通用,设备,命令,目录,后缀,表示,程序,l

      linux切换管理员命令?

      linux切换管理员命令?,系统,密码,地址,用户,命令,管理,传播,电脑,终端,提示,

      linux超级管理员命令?

      linux超级管理员命令?,系统,手机,密码,软件,电脑,环境,信息,工具,地址,用户,l

      linux用户自定义命令?

      linux用户自定义命令?,系统,时间,标准,软件,项目,电脑,服务,工具,基本知识,

      linux默认浏览器命令?

      linux默认浏览器命令?,环境,系统,发行,工程,工具,浏览器,软件,情况,网站,管

      linux修改日期命令?

      linux修改日期命令?,时间,系统,命令,信息,工具,工作,服务,代码,日期,终端,lin

      linux自定义快捷命令?

      linux自定义快捷命令?,系统,首次,位置,时间,文件,命令,链接,快捷键,终端,桌

      linux打印日期命令?

      linux打印日期命令?,时间,系统,工作,命令,标准,环境,档案,信息,设备,位置,Lin

      linux基本命令日期?

      linux基本命令日期?,时间,系统,命令,管理,工作,网络,工具,基础,标准,环境,详

      linux自定义全局命令?

      linux自定义全局命令?,环境,系统,命令,别名,新增,信息,地方,文件,定义,用户,

      linux默认压缩命令?

      linux默认压缩命令?,系统,名称,命令,文件,工具,软件,目录,选项,文件名,格式,l

      linux默认命令行字体?

      linux默认命令行字体?,系统,工具,等级,数字,百度,情况,代码,终端,字体,字符,l

      linux默认命令行模式?

      linux默认命令行模式?,系统,密码,工具,地方,设计,设备,服务,网络,终端,界面,l

      linux命令提示符默认?

      linux命令提示符默认?,系统,标准,信息,基础,代码,软件,美元,电脑,提示符,用

      linux创建管理员命令?

      linux创建管理员命令?,系统,管理,工具,工作,密码,命令,用户,时间,信息,简介,l

      linux增加默认命令?

      linux增加默认命令?,地址,网络,系统,工作,管理,目录,命令,一致,服务,标准,lin

      linux管理员运行命令?

      linux管理员运行命令?,系统,工作,地址,时间,服务,信息,命令,标准,软件,定期,l