Используя виджеты времени/даты Django в пользовательской форме

В двух словах легко запомнить PECS

  1. Используйте подстановочный символ <? extends T>, если вам нужно извлечь объект типа T из коллекции.
  2. Используйте кнопку <? super T>, если вам нужно поместить объекты типа T в коллекцию.
  3. Если вам нужно удовлетворить обе вещи, ну, не используйте подстановочный знак. Так просто, как это.
167
задан dfarrell07 12 July 2013 в 19:24
поделиться

8 ответов

Растущая сложность этого ответа со временем и много требуемых взломов, вероятно, должны предостеречь Вас против выполнения этого вообще. Это полагается на недокументированные внутренние детали реализации администратора, вероятно, повредится снова в будущих версиях Django и не легче реализовать, чем просто нахождение другого календарного виджета JS и использование это.

Однако вот то, что необходимо сделать, если Вы полны решимости сделать эту работу:

  1. Определяют Ваш собственный подкласс 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()
    
  2. Изменение Ваш URLconf для передачи 'form_class': ProductForm вместо 'модели': продукт к универсальному представлению create_object (это будет означать "от my_app.forms, импортирует ProductForm" вместо "из продукта импорта my_app.models", конечно).

  3. В главе Вашего шаблона, включайте {{form.media}} для вывода ссылок на файлы JavaScript.

  4. И 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 (или null_javascript_catalog, если Вы не используете I18N). Необходимо сделать это сами вместо того, чтобы пройти приложение администрирования, таким образом, это доступно независимо от того, зарегистрированы ли Вы в администратора (спасибо 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 для этого дополнения.

159
ответ дан Community 23 November 2019 в 21:00
поделиться

Поскольку решением является hackish, я думаю с помощью собственного виджета даты/времени с некоторым JavaScript, более выполнимо.

63
ответ дан zgoda 23 November 2019 в 21:00
поделиться

Да, я закончил тем, что переопределил/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)
12
ответ дан 23 November 2019 в 21:00
поделиться

Дополняя ответ 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
ответ дан Alex. S. 23 November 2019 в 21:00
поделиться

Я часто ссылаюсь на этот пост, и обнаружил, что документация определяет немного менее хакерский способ переопределения виджетов по умолчанию.

( Нет необходимости переопределять метод __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

Ссылка ] Типы полей , чтобы найти поля формы по умолчанию.

11
ответ дан 23 November 2019 в 21:00
поделиться

Обновлено решение и обходной путь для 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>

URL. py

(r'^admin/jsi18n/', 'django.views.i18n.javascript_catalog'),
1
ответ дан 23 November 2019 в 21:00
поделиться

Нижеприведенный вариант также будет работать в крайнем случае, если вышеприведенный не сработал

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

5
ответ дан 23 November 2019 в 21:00
поделиться

Начиная с Django 1.2 RC1, если вы используете трюк с виджетом для выбора даты администратора Django, в ваш шаблон необходимо добавить следующее, иначе вы: Вы увидите URL-адрес значка календаря, на который имеется ссылка через "/ missing-admin-media-prefix /".

{% 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>
10
ответ дан 23 November 2019 в 21:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: