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

2025-02-27 09:06:00
admin
原创
53
摘要:问题描述:如何在我的自定义视图中使用默认管理员使用的漂亮的 JavaScript 日期和时间小部件?我查看了Django 表单文档,其中简要提到了 django.contrib.admin.widgets,但我不知道如何使用它?这是我想要应用它的模板。<form action="."...

问题描述:

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

我查看了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 还比较陌生,所以请放轻松...


解决方案 1:

随着时间的推移,这个答案变得越来越复杂,并且需要进行许多黑客攻击,可能应该警告您不要这样做。 它依赖于管理员未记录的内部实现细节,很可能在 Django 的未来版本中再次出现问题,并且实现起来并不比找到另一个 JS 日历小部件并使用它更容易。

话虽如此,如果你决心要做到这一点,你必须做以下事情:

  1. 为你的模型定义你自己的ModelForm子类(最好将它放在你应用程序的 forms.py 中),并告诉它使用AdminDateWidget// AdminTimeWidgetAdminSplitDateTime用你模型中的正确字段名称替换‘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()
  1. 将您的 URLconf 更改为传递'form_class': ProductForm'model': Product通用create_object视图(当然,这意味着from my_app.forms import ProductFormfrom my_app.models import Product不是)。

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

  3. 还有一点比较棘手:管理日期/时间小部件假定已加载 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 的补充。

解决方案 2:

由于该解决方案比较黑客化,我认为使用自己的日期/时间小部件和一些 JavaScript 更为可行。

解决方案 3:

我发现自己经常引用这篇文章,并且发现文档定义了一种稍微不那么复杂的方法来覆盖默认小部件。

不需要重写 ModelForm 的 init 方法

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

表单.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

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

解决方案 4:

我的 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:

是的,我最终覆盖了 /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)

解决方案 6:

从 Django 1.2 RC1 开始,如果您使用 Django 管理日期选择器小部件技巧,则必须将以下内容添加到您的模板中,否则您将看到通过“/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>

解决方案 7:

对于 Django >= 2.0

注意:使用管理小部件来处理日期时间字段并不是一个好主意,因为如果您使用 bootstrap 或任何其他 CSS 框架,管理样式表可能会与您的网站样式表发生冲突。如果您在 bootstrap 上构建网站,请使用我的 bootstrap-datepicker 小部件django-bootstrap-datepicker-plus。

步骤 1:将 URL添加javascript-catalog到您的项目(而非应用程序)的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,
        }

解决方案 8:

作为对 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 %}

解决方案 9:

如果上述方法无效,以下方法也可以作为最后的手段

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

解决方案 10:

2021 年 Django 3 (3.2)的另一个简单解决方案;) 因为 andyw 的解决方案在 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)

解决方案 11:

这是另一个 2020 年的解决方案,灵感来自 @Sandeep。使用此要点中的 MinimalSplitDateTimeMultiWidget ,在如下所示的表单中,我们可以使用现代浏览器日期和时间选择器(例如通过 'type': 'date')。我们不需要任何 JS。

class EditAssessmentBaseForm(forms.ModelForm):
    class Meta:
        model = Assessment
        fields = '__all__'

    begin = DateTimeField(widget=MinimalSplitDateTimeMultiWidget())

在此处输入图片描述

解决方案 12:

那么如何只为你的小部件分配一个类,然后将该类绑定到 JQuery 日期选择器呢?

Django表单.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();

解决方案 13:

更新了SplitDateTimerequired=False 的解决方案和解决方法:

表单.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,)

表单.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'),

解决方案 14:

我用的是这个,它很棒,但是我对这个模板有两个问题:

  1. 对于模板中的每个文件,我都会看见两次日历图标。

  2. 对于 TimeField,我有“输入有效日期” 。

以下是表格的截图

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

表单.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']

解决方案 15:

在 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>

解决方案 16:

我的 Django 设置:1.11 Bootstrap: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 %}

解决方案 17:

2020 年 6 月 3 日(所有答案均无效,您可以尝试我使用的这个解决方案。仅适用于 TimeField)

在表单中使用简单的Charfield时间字段(此示例中为开始结束)。

表单.py

我们可以在这里使用FormModelForm

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

解决方案 18:

最干净的方法(使用 Django 3.2 测试):

from django.contrib import admin
from django.contrib.admin.widgets import AdminSplitDateTime
from django import forms


class MyCustomForm(forms.ModelForm):
    custom_datetime = forms.SplitDateTimeField(widget=AdminSplitDateTime())

    class Meta:
        model = MyModel
        fields = ("custom_datetime",)


class MyModelAdmin(admin.ModelAdmin):
    def my_custom_admin_view(self, request):
        form = MyCustomForm()
        admin_form = admin.helpers.AdminForm(form, [], {}, model_admin=self)
        media = self.media + admin_form.media
        context = {
            "media": media,
            "form": form,
        }
        return render(request, "my_custom_template.html", context)

my_custom_template.html

{% extends "admin/base.html" %}

{% block extrastyle %}
{{ block.super }}
{{ media }}
{% endblock %}

{% block content %}
<form method="post">
{{ form.as_p  }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3878  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2714  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   49  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   49  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   49  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用