Использование виджетов времени / даты Django в пользовательской форме
Вопрос
Как я могу использовать отличные виджеты даты и времени 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, так что, пожалуйста, будьте проще...
Решение
Растущая сложность этого ответа с течением времени и множество необходимых взломов, вероятно, должны предостеречь вас от этого вообще. Он полагается на недокументированные внутренние детали реализации администратора, и, скорее всего, снова сломается в будущих версиях 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': Product в универсальное представление create_object (это будет означать " из my_app.forms import ProductForm " вместо " из my_app.models). Импорт товара " ;, конечно).
В заголовке вашего шаблона добавьте {{form.media}} для вывода ссылок на файлы Javascript.
И хакерская часть: административные виджеты даты / времени предполагают, что материал 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 для администратора (спасибо Алексу за упоминание этого):
<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 (или null_javascript_catalog, если вы не используете I18N). Вы должны сделать это самостоятельно, а не просматривать приложение администратора, чтобы оно было доступно независимо от того, вошли ли вы в систему администратора (спасибо Джереми за указание на это). Пример кода для вашего 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 за это дополнение . р>
Другие советы
Поскольку решение является хакерским, я думаю, что использование собственного виджета даты / времени с некоторым JavaScript более целесообразно.
Да, я переопределил / 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)
Код моей головы для версии 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 %}
Я ловлю себя на том, что часто ссылаюсь на этот пост, и обнаружил, что Документация определяет слегка менее хакерский способ переопределить виджеты по умолчанию.
(Нет необходимости переопределять метод ModelForm __init__ ModelForm)
Тем не менее, вам все равно нужно соответствующим образом настроить свои 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
Ссылка Типы полей чтобы найти поля формы по умолчанию.
Начиная с Django 1.2 RC1, если вы используете трюк с виджетом для выбора даты администратора Django, в шаблон необходимо добавить следующее, или вы увидите ссылку на значок календаря, на которую ссылаются через " / missing-admin -media-приставка / & Quot;. р>
{% 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>
В дополнение к ответу Карла Мейера, я хотел бы прокомментировать, что вам нужно поместить этот заголовок в некоторый допустимый блок (внутри заголовка) в вашем шаблоне.
{% 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 %}
Нижеследующее также будет работать в крайнем случае, если вышеперечисленное не удалось
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 из django.forms.extras.widgets import SelectDateWidget
Как насчет того, чтобы просто присвоить класс вашему виджету и затем связать этот класс с датчиком 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();
Для Django > = 2.0
Примечание. Использование административных виджетов для полей даты и времени не является хорошей идеей, поскольку таблицы стилей администратора могут конфликтовать с таблицами стилей вашего сайта в случае, если вы используете загрузчик или любые другие CSS-фреймворки. Если вы создаете свой сайт на начальной загрузке, используйте мой виджет начальной загрузки bootstap-datepicker django-bootstrap-datepicker- плюс .
Шаг 1: добавьте javascript-каталог
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,
}
Обновленное решение и обходной путь для SplitDateTime с 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'),
Я использую это, это здорово, но у меня есть 2 проблемы с шаблоном:
- Я вижу значки календаря дважды для каждого поданного в шаблоне.
И для временного поля у меня есть 'Введите действительную дату.'
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']
В Django 10. MyProject / urls.py: в начале urlpatterns
from django.views.i18n import JavaScriptCatalog
urlpatterns = [
url(r'^jsi18n/
В моем 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>
, JavaScriptCatalog.as_view(), name='javascript-catalog'),
.
.
.]
В моем template.html:
<*>Моя настройка 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 %}