如何使用默认管理员在我的自定义视图中使用的漂亮的JavaScript日期和时间小部件?
我查看了the Django forms documentation,并简要提到了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事物都是新手,所以请放轻松......
答案 0 :(得分:156)
随着时间的推移,这个答案越来越复杂,以及所需的许多黑客,可能应该提醒你不要这样做。它依赖于管理员的未记录的内部实现细节,很可能在Django的未来版本中再次破解,并且比仅仅找到另一个JS日历小部件并使用它更容易实现。
那就是说,如果你决心做这项工作,这就是你要做的事情:
为您的模型定义自己的ModelForm子类(最好将其放在应用程序中的forms.py中),并告诉它使用AdminDateWidget / AdminTimeWidget / AdminSplitDateTime(将'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()
更改您的URLconf以传递'form_class':ProductForm而不是'model':产品到通用create_object视图(这意味着“来自my_app.forms导入ProductForm”而不是“来自my_app.models导入产品“,当然)。
在模板的标题中,添加{{form.media}}以输出指向Javascript文件的链接。
hacky部分:管理日期/时间小部件假定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>
您可能还希望使用以下管理CSS(感谢Alex提及此内容):
<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)。您必须自己执行此操作,而不是通过管理应用程序,因此无论您是否登录到管理员都可以访问它(感谢Jeremy指出这一点)。您的URLconf示例代码:
(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),
最后,如果您使用的是Django 1.2或更高版本,则模板中需要一些额外的代码来帮助小部件找到他们的媒体:
{% 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添加此内容。
答案 1 :(得分:63)
由于解决方案是hackish,我认为使用自己的日期/时间小部件和一些JavaScript更可行。
答案 2 :(得分:12)
是的,我最终覆盖了/ admin / jsi18n / url。
这是我在urls.py中添加的内容。确保它在/ admin / url
之上 (r'^admin/jsi18n', i18n_javascript),
这是我创建的i18n_javascript函数。
from django.contrib import admin
def i18n_javascript(request):
return admin.site.i18n_javascript(request)
答案 3 :(得分:11)
我发现自己经常引用这篇文章,并发现documentation定义了一种略微的黑客方式来覆盖默认小部件。
(无需覆盖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
引用Field Types以查找默认表单字段。
答案 4 :(得分:11)
我的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 %}
答案 5 :(得分:10)
从Django 1.2 RC1开始,如果您正在使用Django管理日期选择器widge技巧,则必须将以下内容添加到您的模板中,否则您将看到通过“/ missing-admin-引用的日历图标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>
答案 6 :(得分:7)
作为对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 %}
答案 7 :(得分:5)
如果上述失败
,以下内容也将作为最后的手段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
答案 8 :(得分:3)
如果只为窗口小部件分配一个类,然后将该类绑定到JQuery日期选择器呢?
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();
答案 9 :(得分:3)
注意:在日期时间字段中使用管理窗口小部件不是一个好主意,因为在使用引导程序或任何其他CSS框架的情况下,管理样式表可能会与您的网站样式表发生冲突。如果您要在Bootstrap上构建网站,请使用我的bootstrap-datepicker小部件django-bootstrap-datepicker-plus。
第1步:将javascript-catalog
URL添加到项目(而非应用程序)的urls.py
文件中。
from django.views.i18n import JavaScriptCatalog
urlpatterns = [
path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]
步骤2:将所需的JavaScript / CSS资源添加到模板中。
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static '/admin/js/core.js' %}"></script>
<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
中使用管理窗口小部件作为日期时间输入字段。
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,
}
答案 10 :(得分:1)
我用这个很好,但是模板有两个问题:
对于TimeField,我具有“ 输入有效日期。”
models.py
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
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']
答案 11 :(得分:1)
使用必需=错误更新了 SplitDateTime 的解决方案和解决方法:
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'),
答案 12 :(得分:1)
这是另一个受@Sandeep启发的2020解决方案。使用以下gist中的MinimalSplitDateTimeMultiWidget,在下面的窗体中,我们可以使用现代的浏览器日期和时间选择器(例如,通过'type':'date')。我们不需要任何JS。
class EditAssessmentBaseForm(forms.ModelForm):
class Meta:
model = Assessment
fields = '__all__'
begin = DateTimeField(widget=MinimalSplitDateTimeMultiWidget())
答案 13 :(得分:1)
2021 年 Django 3 (3.2) 的另一个简单解决方案 ;) 导致 andyw 的解决方案在 web Firefox 中不起作用...
{% load static %}
{% block extrahead %}
{{ block.super }}
<script type="text/javascript" src="{% static 'admin/js/cancel.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}">
<script src="{% url 'admin:jsi18n' %}"></script>
<script src="{% static 'admin/js/jquery.init.js' %}"></script>
<script src="{% static 'admin/js/core.js' %}"></script>
{{ form.media }}
{% endblock %}
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Сохранить">
</form>
然后你就可以使用你的表单了。 例子:
from django.contrib.admin import widgets
date_time = forms.SplitDateTimeField(widget=widgets.AdminSplitDateTime)
答案 14 :(得分:0)
在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>
答案 15 :(得分:0)
我的Django设置:1.11 引导程序:3.3.7
由于没有一个答案是完全清楚的,所以我共享我的模板代码,该代码完全没有错误。
模板的上半部分:
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block head %}
<title>Add Interview</title>
{% endblock %}
{% block content %}
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<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' %}"></script>
下半部:
<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.min.js' %}"></script>
{% endblock %}
答案 16 :(得分:0)
2020年6月3日(所有答案均无效,您可以尝试使用我曾使用的此解决方案。仅用于TimeField)
对表单中的时间字段(在此示例中为开始和结束)使用简单的Charfield
。
forms.py
我们可以在此处使用Form
或ModelForm
。
class TimeSlotForm(forms.ModelForm):
start = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))
end = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))
class Meta:
model = TimeSlots
fields = ('start', 'end', 'provider')
将字符串输入转换为视图中的时间对象。
import datetime
def slots():
if request.method == 'POST':
form = create_form(request.POST)
if form.is_valid():
slot = form.save(commit=False)
start = form.cleaned_data['start']
end = form.cleaned_data['end']
start = datetime.datetime.strptime(start, '%H:%M').time()
end = datetime.datetime.strptime(end, '%H:%M').time()
slot.start = start
slot.end = end
slot.save()