استخدام عناصر واجهة المستخدم للوقت/التاريخ في Django في نموذج مخصص

StackOverflow https://stackoverflow.com/questions/38601

  •  09-06-2019
  •  | 
  •  

سؤال

كيف يمكنني استخدام أدوات التاريخ والوقت الأنيقة في JavaScript والتي يستخدمها المسؤول الافتراضي مع طريقة العرض المخصصة الخاصة بي؟

لقد نظرت من خلال وثائق نماذج جانغو, ، ويذكر بإيجاز 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 آخر واستخدامه.

ومع ذلك، إليك ما عليك فعله إذا كنت مصممًا على إنجاز هذا العمل:

  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":نموذج المنتج بدلاً من "النموذج":المنتج إلى طريقة العرض create_object العامة (وهذا يعني "من my_app.forms استيراد ProductForm" بدلاً من "من my_app.models استيراد المنتج"، بالطبع).

  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>
    

    قد ترغب أيضًا في استخدام المشرف التالي 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>

شكرًا com.lupefiasco لهذه الإضافة.

نصائح أخرى

نظرًا لأن الحل غير متقن، أعتقد أن استخدام أداة التاريخ/الوقت الخاصة بك مع بعض جافا سكريبت أكثر جدوى.

نعم، انتهى بي الأمر بتجاوز /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 %}

أجد نفسي أشير إلى هذا المنشور كثيرًا، ووجدت أن توثيق يحدد أ طفيف طريقة أقل اختراقًا لتجاوز الأدوات الافتراضية.

(ليست هناك حاجة لتجاوز طريقة __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، فيجب إضافة ما يلي إلى القالب الخاص بك، أو سترى عنوان 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>

استكمالًا لإجابة كارل ماير، أود أن أعلق على أنك تحتاج إلى وضع هذا الرأس في كتلة صالحة (داخل الرأس) داخل القالب الخاص بك.

{% 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 الخاص بك from django.forms.extras.widgets import SelectDateWidget

ماذا عن مجرد تعيين فئة لعنصر واجهة المستخدم الخاص بك ثم ربط هذه الفئة بمنتقي البيانات JQuery؟

نماذج جانغو.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'

وبعض جافا سكريبت للقالب:

  $(".datepicker").datepicker();

لجانغو>= 2.0

ملحوظة:لا يعد استخدام عناصر واجهة المستخدم الإدارية لحقول التاريخ والوقت فكرة جيدة حيث يمكن أن تتعارض أوراق أنماط الإدارة مع أوراق أنماط موقعك في حالة استخدام bootstrap أو أي أطر عمل 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,
        }

تم تحديث الحل والحل البديل لـ 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'),

أستخدم هذا، إنه رائع، لكن لدي مشكلتان في القالب:

  1. أرى أيقونات التقويم مرتين لكل قدم في القالب.
  2. وبالنسبة لـ TimeField لدي "أدخل تاريخًا صالحًا.'

    Here is a screenshot of the Form

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']

في جانغو 10.myproject/urls.py:في بداية أنماط url

  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>

إعداد جانغو الخاص بي: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 %}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top