Domanda

Come posso utilizzare gli eleganti widget JavaScript di data e ora che l'amministratore predefinito utilizza con la mia visualizzazione personalizzata?

Ho guardato attentamente la documentazione dei moduli Django, e menziona brevemente django.contrib.admin.widgets, ma non so come usarlo?

Ecco il mio modello su cui voglio che venga applicato.

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

Inoltre, penso che sia opportuno notare che non ho scritto personalmente una visualizzazione per questo modulo, sto utilizzando una visualizzazione generica.Ecco la voce da url.py:

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

E sono relativamente nuovo nell'intera faccenda di Django/MVC/MTV, quindi per favore vacci piano...

È stato utile?

Soluzione

La crescente complessità di questa risposta nel tempo e i numerosi hack richiesti probabilmente dovrebbero metterti in guardia dal farlo.Si basa su dettagli di implementazione interni non documentati dell'amministratore, è probabile che si interrompa di nuovo nelle versioni future di Django e non è più semplice da implementare che semplicemente trovare un altro widget del calendario JS e utilizzarlo.

Detto questo, ecco cosa devi fare se sei determinato a far funzionare tutto questo:

  1. Definisci la tua sottoclasse ModelForm per il tuo modello (meglio inserirla in Forms.py nella tua app) e digli di utilizzare AdminDateWidget / AdminTimeWidget / AdminSplitDateTime (sostituisci 'mydate' ecc. con i nomi di campo corretti dal tuo modello):

    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. Cambia il tuo URLconf per passare 'form_class':ProductForm invece di 'modello':Product nella vista generica create_object (che significherà "from my_app.forms import ProductForm" invece di "from my_app.models import Product", ovviamente).

  3. Nell'intestazione del modello, includi {{ form.media }} per visualizzare i collegamenti ai file Javascript.

  4. E la parte complicata:i widget data/ora dell'amministratore presumono che il materiale i18n JS sia stato caricato e richiedono anche core.js, ma non ne forniscono nessuno automaticamente.Quindi nel tuo modello sopra {{ form.media }} avrai bisogno di:

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

    Potresti anche voler utilizzare il seguente CSS di amministrazione (grazie Alex per aver menzionato questo):

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

Ciò implica che il supporto di amministrazione di Django (ADMIN_MEDIA_PREFIX) si trova in /media/admin/: puoi modificarlo per la tua configurazione.Idealmente utilizzeresti un processore di contesto per passare questi valori al tuo modello invece di codificarlo, ma questo va oltre lo scopo di questa domanda.

Ciò richiede anche che l'URL /my_admin/jsi18n/ sia collegato manualmente alla vista django.views.i18n.javascript_catalog (o null_javascript_catalog se non stai utilizzando I18N).Devi farlo da solo invece di passare attraverso l'applicazione di amministrazione in modo che sia accessibile indipendentemente dal fatto che tu abbia effettuato l'accesso all'amministratore (grazie Jeremy per averlo sottolineato).Codice di esempio per il tuo URLconf:

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

Infine, se stai utilizzando Django 1.2 o versione successiva, avrai bisogno di codice aggiuntivo nel tuo modello per aiutare i widget a trovare i loro contenuti multimediali:

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

Grazie lupefiasco per questa aggiunta.

Altri suggerimenti

Poiché la soluzione è hacker, penso che utilizzare il proprio widget data/ora con un po' di JavaScript sia più fattibile.

Sì, ho finito per sovrascrivere l'URL /admin/jsi18n/.

Ecco cosa ho aggiunto nel mio urls.py.Assicurati che sia sopra l'URL /admin/

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

Ed ecco la funzione i18n_javascript che ho creato.

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

Il mio codice principale per la versione 1.4 (alcuni nuovi e altri rimossi)

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

Mi ritrovo a fare spesso riferimento a questo post e ho scoperto che il documentazione definisce a leggermente modo meno complicato per sovrascrivere i widget predefiniti.

(Non è necessario sovrascrivere il metodo __init__ di ModelForm)

Tuttavia, è comunque necessario collegare JS e CSS in modo appropriato, come menzionato da Carl.

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

Riferimento Tipi di campo per trovare i campi del modulo predefiniti.

A partire da Django 1.2 RC1, se stai utilizzando il trucco del widget di selezione della data dell'amministratore di Django, è necessario aggiungere quanto segue al tuo modello, altrimenti vedrai l'URL dell'icona del calendario a cui si fa riferimento tramite "/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>

A complemento della risposta di Carl Meyer, vorrei commentare che è necessario inserire l'intestazione in un blocco valido (all'interno dell'intestazione) all'interno del modello.

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

Quanto segue funzionerà anche come ultima risorsa se quanto sopra fallisce

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

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

Uguale a

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

    class Meta:
        model = Payments

inseriscilo nel tuo Forms.py from django.forms.extras.widgets import SelectDateWidget

Che ne dici di assegnare semplicemente una classe al tuo widget e quindi associare quella classe al datepicker JQuery?

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

E alcuni JavaScript per il modello:

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

Per Django >= 2.0

Nota:Utilizzare i widget di amministrazione per i campi data-ora non è una buona idea poiché i fogli di stile di amministrazione possono entrare in conflitto con i fogli di stile del tuo sito nel caso in cui utilizzi bootstrap o qualsiasi altro framework CSS.Se stai costruendo il tuo sito su bootstrap usa il mio widget bootstrap-datepicker django-bootstrap-datepicker-plus.

Passo 1: Aggiungere javascript-catalog URL del tuo progetto (non dell'app) urls.py file.

from django.views.i18n import JavaScriptCatalog

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

Passo 2: Aggiungi le risorse JavaScript/CSS richieste al tuo modello.

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

Passaggio 3: Utilizza i widget di amministrazione per i campi di input di data e ora nel tuo 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,
        }

Soluzione aggiornata e soluzione alternativa per SplitDateTime con richiesto=falso:

forme.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,)

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

Io uso questo, è fantastico, ma ho 2 problemi con il modello:

  1. Vedo le icone del calendario due volte per ogni modello archiviato.
  2. E per TimeField ho 'Inserisci una data valida.'

    Here is a screenshot of the Form

modelli.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)

forme.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 Django10.mioprogetto/urls.py:all'inizio di urlpatterns

  from django.views.i18n import JavaScriptCatalog

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

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

La mia configurazione Django:1.11 bootstrap:3.3.7

Poiché nessuna delle risposte è completamente chiara, condivido il codice del mio modello che non presenta alcun errore.

Metà superiore del modello:

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

La metà inferiore:

<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 %}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top