在自定义表单中使用Django时间/date小部件

我如何使用默认pipe理员使用我的自定义视图的漂亮的JavaScriptdate和时间小部件?

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

这是我希望应用的模板。

<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的条目:

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

而我相当新的整个Django / MVC / MTV的东西,所以请容易…

随着时间的推移,这个答案越来越复杂,需要许多黑客,可能应该提醒你不要这样做。 它依赖于pipe理员未公开的内部实现细节,在未来的Django版本中很可能会再次被破坏,而且不仅仅是寻找另一个JS日历小部件,而是使用它。

这就是说,如果你决定做这个工作,你需要做的是:

  1. 为你的模型定义你自己的ModelForm子类(最好把它放在你的应用程序中的forms.py中),并告诉它使用AdminDateWidget / AdminTimeWidget / AdminSplitDateTime(用你的模型中正确的字段名replace'mydate'等):

     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() 
  2. 改变你的URLconf以传递'form_class':ProductForm而不是'model':产品到通用的create_object视图(当然,这意味着“from my_app.forms import ProductForm”而不是“from my_app.models import Product”)。

  3. 在模板的头部,包含{{form.media}}以将链接输出到Javascript文件。

  4. 和hacky部分:pipe理date/时间小部件假定i18n JS的东西已经加载,也需要core.js,但不提供任何一个自动。 所以在上面的{{form.media}}你的模板中,你需要:

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

    你也可以使用下面的pipe理CSS(感谢亚历克斯提到这一点):

     <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的pipe理媒体(ADMIN_MEDIA_PREFIX)在/ media / admin / – 你可以改变你的设置。 理想情况下,您可以使用上下文处理器将此值传递给您的模板,而不是对其进行硬编码,但这超出了此问题的范围。

这也要求将URL / my_admin / jsi18n /手动连接到django.views.i18n.javascript_catalog视图(如果不使用I18N,则为null_javascript_catalog)。 你必须自己做,而不是通过pipe理应用程序,所以无论你是否loginpipe理员(感谢杰里米指出这一点),它是可访问的。 您的URLconf的示例代码:

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

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

 {% 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 %}"; </script> 

感谢lupefiasco为此增加。

由于解决scheme是hackish,我认为使用一些JavaScript的自己的date/时间小部件更可行。

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

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

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

这里是我创build的i18n_javascript函数。

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

从Django 1.2 RC1开始,如果您使用的是Djangopipe理员dateselect器窗口技巧,则必须将以下内容添加到您的模板中,否则您将看到通过“/ missing-admin-media-prefix”引用的日历图标url /”。

 {% 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 %}"; </script> 

我发现自己引用了这个post很多,发现文档定义了一个稍微不好用的方法来覆盖默认的小部件。

不需要重写ModelForm的__init__方法

但是,您仍然需要像Carl提到的那样适当地连接您的JS和CSS。

forms.py

 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 

参考字段types来查找默认的表单字段。

我的1.4版本的头部代码(一些新的和一些删除)

 {% 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> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/core.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.init.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/actions.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/calendar.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/DateTimeShortcuts.js"></script> {% endblock %} 

作为Carl Meyer的补充,我想评论一下,你需要把这个头部放在你的模板中的某个有效块(头部内)。

 {% 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> <script type="text/javascript" src="/media/admin/js/core.js"></script> <script type="text/javascript" src="/media/admin/js/admin/RelatedObjectLookups.js"></script> {{ form.media }} {% endblock %} 

(我试图对build议推出自己的日历小部件的人发表评论,但是我没有看到评论button,或者我没有足够的代表。

干什么? 我认为这将是最好的重新使用pipe理小部件,但也许它应该从pipe理员分开,并更容易使用。 感谢这些信息。

我终于设法让这个小工具在开发服务器上工作,只是为了让它在部署中断。 我终于决定不值得在我的网站上使用武力,并写下我自己的小部件。 它不是那么灵活,但它可能适用于很多人: http : //www.copiesofcopies.org/webl/?p=81

如果上述失败,下面还将作为最后的手段

 class PaymentsForm(forms.ModelForm): class Meta: model = Payments def __init__(self, *args, **kwargs): super(PaymentsForm, self).__init__(*args, **kwargs) self.fields['date'].widget = SelectDateWidget() 

与…一样

 class PaymentsForm(forms.ModelForm): date = forms.DateField(widget=SelectDateWidget()) class Meta: model = Payments 

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

那么只是给你的小部件分配一个类,然后将该类绑定到JQuery datepicker呢?

Django forms.py:

 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的模板:

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

SplitDateTime的更新解决scheme和解决方法,使用required = False

forms.py

 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

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

urls.py

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

在Django 10. myproject / urls.py:在urlpatterns的开头

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

在我的template.html中:

 {% load staticfiles %} <script src="{% static "js/jquery-2.2.3.min.js" %}"></script> <script src="{% static "js/bootstrap.min.js" %}"></script> {# Loading internazionalization for js #} {% load i18n admin_modify %} <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script> <script type="text/javascript" src="{% static "/admin/js/jquery.init.js" %}"></script> <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> <script type="text/javascript" src="{% static "/admin/js/SelectFilter2.js" %}"></script> <script type="text/javascript" src="{% static "/admin/js/admin/RelatedObjectLookups.js" %}"></script> <script type="text/javascript" src="{% static "/admin/js/actions.js" %}"></script> <script type="text/javascript" src="{% static "/admin/js/calendar.js" %}"></script> <script type="text/javascript" src="{% static "/admin/js/admin/DateTimeShortcuts.js" %}"></script>