Frage

Wie kann ich die praktischen JavaScript-Widgets für Datum und Uhrzeit verwenden, die der Standardadministrator mit meiner benutzerdefinierten Ansicht verwendet?

Ich habe durchgeschaut die Django-Formulardokumentation, und es erwähnt kurz django.contrib.admin.widgets, aber ich weiß nicht, wie ich es verwenden soll?

Hier ist meine Vorlage, auf die ich sie anwenden möchte.

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

Außerdem sollte meiner Meinung nach beachtet werden, dass ich selbst keine eigene Ansicht für dieses Formular geschrieben habe, sondern eine generische Ansicht verwende.Hier ist der Eintrag aus der url.py:

(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

Und ich bin relativ neu in der ganzen Django/MVC/MTV-Sache, also gehen Sie bitte ruhig vor ...

War es hilfreich?

Lösung

Die zunehmende Komplexität dieser Antwort im Laufe der Zeit und die vielen erforderlichen Hacks sollten Sie wahrscheinlich davor warnen, dies überhaupt zu tun.Es stützt sich auf undokumentierte interne Implementierungsdetails des Administrators, wird in zukünftigen Versionen von Django wahrscheinlich erneut scheitern und ist nicht einfacher zu implementieren, als einfach ein anderes JS-Kalender-Widget zu finden und dieses zu verwenden.

Das heißt, Folgendes müssen Sie tun, wenn Sie entschlossen sind, dass dies funktioniert:

  1. Definieren Sie Ihre eigene ModelForm-Unterklasse für Ihr Modell (fügen Sie sie am besten in „forms.py“ in Ihrer App ein) und weisen Sie sie an, AdminDateWidget / AdminTimeWidget / AdminSplitDateTime zu verwenden (ersetzen Sie „mydate“ usw. durch die richtigen Feldnamen aus Ihrem Modell):

    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. Ändern Sie Ihre URLconf, um „form_class“ zu übergeben:ProductForm statt 'model':Product in die generische Ansicht „create_object“ einfügen (das bedeutet natürlich „from my_app.forms import ProductForm“ statt „from my_app.models import Product“).

  3. Fügen Sie im Kopf Ihrer Vorlage {{ form.media }} ein, um die Links zu den Javascript-Dateien auszugeben.

  4. Und der Hacky-Teil:Die Admin-Datums-/Uhrzeit-Widgets gehen davon aus, dass das i18n JS-Material geladen wurde, und erfordern auch core.js, stellen jedoch keines davon automatisch bereit.In Ihrer Vorlage oben {{ form.media }} benötigen Sie also:

    <script type="text/javascript" src="/my_admin/jsi18n/"></script>
    <script type="text/javascript" src="/media/admin/js/core.js"></script>
    

    Möglicherweise möchten Sie auch das folgende Admin-CSS verwenden (danke). Alex für die Erwähnung):

    <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"/>
    

Dies bedeutet, dass sich Djangos Admin-Medien (ADMIN_MEDIA_PREFIX) unter /media/admin/ befinden – Sie können dies für Ihr Setup ändern.Idealerweise würden Sie einen Kontextprozessor verwenden, um diese Werte an Ihre Vorlage zu übergeben, anstatt sie fest zu codieren, aber das würde den Rahmen dieser Frage sprengen.

Dies erfordert auch, dass die URL /my_admin/jsi18n/ manuell mit der Ansicht django.views.i18n.javascript_catalog verknüpft wird (oder null_javascript_catalog, wenn Sie I18N nicht verwenden).Sie müssen dies selbst tun, anstatt die Admin-Anwendung zu verwenden, damit Sie darauf zugreifen können, unabhängig davon, ob Sie beim Admin angemeldet sind (danke). Jeremy für den Hinweis).Beispielcode für Ihre URLconf:

(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

Wenn Sie Django 1.2 oder höher verwenden, benötigen Sie schließlich zusätzlichen Code in Ihrer Vorlage, der den Widgets hilft, ihre Medien zu finden:

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

Danke Lupefiasko für diesen Zusatz.

Andere Tipps

Da die Lösung hackig ist, halte ich die Verwendung eines eigenen Datums-/Uhrzeit-Widgets mit etwas JavaScript für praktikabler.

Ja, am Ende habe ich die URL /admin/jsi18n/ überschrieben.

Folgendes habe ich in meiner urls.py hinzugefügt.Stellen Sie sicher, dass es sich über der URL /admin/ befindet

    (r'^admin/jsi18n', i18n_javascript),

Und hier ist die i18n_javascript-Funktion, die ich erstellt habe.

from django.contrib import admin
def i18n_javascript(request):
  return admin.site.i18n_javascript(request)

Mein Kopfcode für Version 1.4 (einige neu und einige entfernt)

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

Ich beziehe mich oft auf diesen Beitrag und habe festgestellt, dass der Dokumentation definiert a leicht weniger umständliche Möglichkeit, Standard-Widgets zu überschreiben.

(Es ist nicht erforderlich, die __init__-Methode von ModelForm zu überschreiben)

Allerdings müssen Sie Ihr JS und CSS immer noch entsprechend verkabeln, wie Carl erwähnt.

Formen.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

Referenz Feldtypen um die Standardformularfelder zu finden.

Wenn Sie ab Django 1.2 RC1 den Django-Administrator-Datumsauswahl-Widget-Trick verwenden, muss Folgendes zu Ihrer Vorlage hinzugefügt werden, sonst wird die URL des Kalendersymbols durch „/missing-admin-media-prefix“ referenziert /".

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

Ergänzend zur Antwort von Carl Meyer möchte ich anmerken, dass Sie diesen Header in einen gültigen Block (innerhalb des Headers) Ihrer Vorlage einfügen müssen.

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

Das Folgende funktioniert auch als letzter Ausweg, wenn das oben Genannte fehlschlägt

class PaymentsForm(forms.ModelForm):
    class Meta:
        model = Payments

    def __init__(self, *args, **kwargs):
        super(PaymentsForm, self).__init__(*args, **kwargs)
        self.fields['date'].widget = SelectDateWidget()

Gleich wie

class PaymentsForm(forms.ModelForm):
    date = forms.DateField(widget=SelectDateWidget())

    class Meta:
        model = Payments

Fügen Sie dies in Ihre Forms.py ein from django.forms.extras.widgets import SelectDateWidget

Wie wäre es, wenn Sie Ihrem Widget einfach eine Klasse zuweisen und diese Klasse dann an den JQuery-Datumswähler binden?

Django-Formulare.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'

Und etwas JavaScript für die Vorlage:

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

Für Django >= 2.0

Notiz:Die Verwendung von Admin-Widgets für Datums-/Uhrzeitfelder ist keine gute Idee, da Admin-Stylesheets mit den Stylesheets Ihrer Website in Konflikt geraten können, falls Sie Bootstrap oder andere CSS-Frameworks verwenden.Wenn Sie Ihre Website auf Bootstrap erstellen, verwenden Sie mein Bootstrap-Datepicker-Widget django-bootstrap-datepicker-plus.

Schritt 1: Hinzufügen javascript-catalog URL zu Ihrem Projekt (nicht zu Ihrer App) urls.py Datei.

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

Schritt 2: Fügen Sie Ihrer Vorlage erforderliche JavaScript-/CSS-Ressourcen hinzu.

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

Schritt 3: Verwenden Sie Admin-Widgets für Datums- und Uhrzeiteingabefelder in Ihrem 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,
        }

Aktualisierte Lösung und Problemumgehung für SplitDateTime mit erforderlich=Falsch:

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

Ich verwende das, es ist großartig, aber ich habe zwei Probleme mit der Vorlage:

  1. Ich sehe die Kalendersymbole zweimal für jede eingereichte Vorlage.
  2. Und für TimeField habe ich 'Gib ein gültiges Datum ein.'

    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)

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

In Django 10.meinprojekt/urls.py:am Anfang von URL-Mustern

  from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
.
.
.]

In meiner 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>

Mein Django-Setup:1.11 Bootstrap:3.3.7

Da keine der Antworten völlig klar ist, teile ich meinen Vorlagencode, der überhaupt keine Fehler aufweist.

Obere Hälfte der Vorlage:

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

Untere Hälfte:

<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 %}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top