사용자 정의 양식에서 Django 시간 / 날짜 위젯 사용


171

기본 관리자가 사용자 정의보기와 함께 사용하는 멋진 JavaScript 날짜 및 시간 위젯을 사용하려면 어떻게해야합니까?

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': ''}),

그리고 나는 장고 / MVC / MTV 전체에 대해 새롭기 때문에 쉽게 가십시오 ...



답변:


159

시간이 지남에 따라이 답변의 복잡성이 증가하고 많은 해킹이 필요하므로 아마도이 작업을 수행하지 않도록주의해야합니다. 그것은 문서화되지 않은 관리자의 내부 구현 세부 사항에 의존하고 있으며 장고의 장래 버전에서 다시 깨질 가능성이 있으며 다른 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': 'model'대신 ProductForm : Product를 일반 create_object보기로 전달하도록 변경하십시오 (물론 "my_app.models import Product"대신 "my_app.forms import ProductForm"을 의미 함).

  3. 템플리트 헤드에 {{form.media}}를 포함시켜 Javascript 파일에 대한 링크를 출력하십시오.

  4. 그리고 해키 부분 : 관리 날짜 / 시간 위젯은 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>

    Alex 에게 다음과 같은 관리자 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보기 (또는 I18N을 사용하지 않는 경우 null_javascript_catalog)에 수동으로 연결해야합니다. 관리자에게 로그인했는지 여부에 관계없이 액세스 할 수 있도록 관리자 응용 프로그램을 거치지 않고 직접해야합니다 ( 제레미 가 이것을 지적 해 주셔서 감사 합니다). 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 에게 감사드립니다 .


3
온라인에서이 작업을 수행하는 데 가장 유용한 게시물이지만 마지막으로 날짜 / 시간 위젯이 표시되고 채우는 필드가 이제 양식 필드에 required = False 임에도 불구하고 "유효한 날짜 / 시간을 입력하십시오"라는 메시지가 표시되므로 필드를 채우는 중입니다. 비워두면 필수 필드가 아닙니다. 나를 위해 jquery로 돌아갑니다.
PhoebeB

이것이 장고 1.1.1로가는 길입니까?
Nacho

1
Django 1.2 RC1 이상에서는 위의 내용을 약간 변경해야합니다. 참조 : stackoverflow.com/questions/38601/...
mshafrir

1
이것이 여전히 장고 1.4에 적용되는지 알고 있습니까? jQuery의 datepicker를 사용한다고 확신하지만 Django 팀이 위젯을 더 공개적으로 사용할 수 있는지 궁금합니다. (이 QA가 가장 많은 문서 인 것 같지 않습니다.)
John C

1
관리자 위젯을 관리자 외부에서 더 쉽게 재사용 할 수 있도록하는 움직임은 없었으며, 어떤 것도있을 것 같지는 않습니다. 그것은 많은 작업이 될 것이고, 우선 순위가 훨씬 높은 항목이 있습니다. (저는 Django 핵심 팀 btw입니다.)
Carl Meyer

64

솔루션이 hackish이기 때문에 JavaScript와 함께 날짜 / 시간 위젯을 사용하는 것이 더 적합하다고 생각합니다.


8
나는 동의한다. 몇 달 전에 django 프로젝트 로이 작업을 시도했습니다. 나는 결국 포기하고 jQueryUI로 내 자신을 추가했습니다. 작동하도록 10 분을 모두 걸렸습니다.
Pricec 2016 년

8
기록을 위해, 나는이 답변을 찬성했고 나는 실제로 프로덕션 사이트에서 내 답변에이 기술을 사용한 적이 없다 ;-)
Carl Meyer

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)

아, 아주 좋은 지적입니다. 위의 답변에 이것을 추가하여 사람들이 어려움을 겪기 전에 쉽게 찾을 수 있습니다.
Carl Meyer

12

나는이 게시물을 많이 참조하고 문서에서 기본 위젯을 무시 하는 약간 덜 해킹 된 방법을 정의 한다는 것을 알았습니다 .

( 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

기본 양식 필드를 찾기위한 참조 필드 유형 .


5
나는이 접근법이 덜 해킹 적이라는 것에 동의하지 않는다. 더 멋지게 보이지만 모델 양식으로 생성 된 양식 필드를 완전히 재정의하면 help_text와 같은 모델 필드에서 옵션을 지울 수도 있습니다. init을 재정의 하면 위젯 만 변경하고 나머지 양식 필드는 그대로 둡니다.
Carl Meyer

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 %}

3
대박 . 나는 지난 2 주 동안 이것을 시도하고 있었고 이것은 매우 감사합니다
numerah

Django 1.4 이상에는 {{STATIC_URL}} 또는 {% load staticfiles %}을 (를) 사용하지 않아야합니다. 전체 MEDIA_URL 네임 스페이스는 더 이상 사용되지 않고 제거되었으므로 Django 1.4+에는 필수입니다. 은 / 관리 / jsi18n 결의, 당신은 제대로 경우 ^ 관리 / 서버 / urls.py에 매핑
jeberle

장고 1.4의 경우 유용한 유용한 것들
Ashish

10

Django 1.2 RC1부터 Django 관리자 날짜 선택기 widge 트릭을 사용하는 경우 다음을 템플릿에 추가해야합니다. 그렇지 않으면 "/ 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

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 %}

또한이 링크가 유용하다는 것을 알았습니다 : groups.google.ca/group/django-users/msg/1a40cf5f153cd23e
Alex. S.

6

장고> = 2.0

참고 : 부트 스트랩 또는 다른 CSS 프레임 워크를 사용하는 경우 관리 스타일 시트가 사이트 스타일 시트와 충돌 할 수 있으므로 날짜-시간 필드에 관리 위젯을 사용하는 것은 좋지 않습니다. 부트 스트랩에 사이트를 구축하는 경우 내 bootstrap-datepicker 위젯 django-bootstrap-datepicker-plus를 사용하십시오 .

1 단계 :javascript-catalog 프로젝트 (앱이 아닌) urls.py파일에 URL을 추가 합니다.

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,
        }

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

양식에 넣으십시오 .py from django.forms.extras.widgets import SelectDateWidget


1
'DateField'객체에 'needs_multipart_form'속성이 없습니다.
madeeha ameer

3

위젯에 클래스를 할당 한 다음 해당 클래스를 JQuery 날짜 선택기에 바인딩하면 어떻습니까?

장고 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();


1

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'),

나는 또한 SplitDateTime 위젯을 해결하기 위해 티켓 채운 code.djangoproject.com/ticket/12303을
샘 A.

1

나는 이것을 사용하지만 훌륭하지만 템플릿에 두 가지 문제가 있습니다.

  1. 템플릿에 제출할 때마다 캘린더 아이콘이 두 번 표시 됩니다.
  2. 그리고 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']

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>

0

내 장고 설정 : 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 %}

0

2020 년 6 월 3 일 (모든 답변이 효과가 없었습니다.이 솔루션을 사용해 볼 수 있습니다.

양식에서 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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.