Pregunta

¿Cómo puedo utilizar los ingeniosos widgets de fecha y hora de JavaScript que utiliza el administrador predeterminado con mi vista personalizada?

he mirado a través la documentación de formularios de Django, y menciona brevemente django.contrib.admin.widgets, pero no sé cómo usarlo.

Aquí está mi plantilla en la que quiero que se aplique.

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

Además, creo que cabe señalar que en realidad no he escrito una vista para este formulario, estoy usando una vista genérica.Aquí está la entrada de url.py:

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

Y soy relativamente nuevo en todo el asunto Django/MVC/MTV, así que, por favor, hazlo con calma...

¿Fue útil?

Solución

La creciente complejidad de esta respuesta a lo largo del tiempo y los numerosos trucos necesarios probablemente deberían advertirle que no haga esto.Se basa en detalles de implementación internos no documentados del administrador, es probable que vuelva a fallar en futuras versiones de Django y no es más fácil de implementar que simplemente encontrar otro widget de calendario JS y usarlo.

Dicho esto, esto es lo que debe hacer si está decidido a que esto funcione:

  1. Defina su propia subclase ModelForm para su modelo (es mejor colocarla en form.py en su aplicación) y dígale que use AdminDateWidget / AdminTimeWidget / AdminSplitDateTime (reemplace 'mydate', etc. con los nombres de campo adecuados de su modelo):

    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. Cambie su URLconf para pasar 'form_class':ProductForm en lugar de 'modelo':Producto a la vista genérica create_object (eso significará "desde my_app.forms importar ProductForm" en lugar de "desde my_app.models importar producto", por supuesto).

  3. En el encabezado de su plantilla, incluya {{ form.media }} para generar los enlaces a los archivos Javascript.

  4. Y la parte complicada:los widgets de fecha/hora del administrador suponen que el material i18n JS se ha cargado y también requieren core.js, pero no proporcionan ninguno de ellos automáticamente.Entonces, en tu plantilla de arriba {{ form.media }} necesitarás:

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

    También es posible que desee utilizar el siguiente CSS de administrador (gracias Alex por mencionar esto):

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

Esto implica que los medios de administración de Django (ADMIN_MEDIA_PREFIX) están en /media/admin/; puedes cambiar eso para tu configuración.Lo ideal sería utilizar un procesador de contexto para pasar estos valores a su plantilla en lugar de codificarlos, pero eso está más allá del alcance de esta pregunta.

Esto también requiere que la URL /my_admin/jsi18n/ esté conectada manualmente a la vista django.views.i18n.javascript_catalog (o null_javascript_catalog si no está usando I18N).Tienes que hacerlo tú mismo en lugar de pasar por la aplicación de administración para que sea accesible independientemente de si has iniciado sesión en el administrador (gracias jeremy por señalarlo).Código de muestra para su URLconf:

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

Por último, si estás usando Django 1.2 o posterior, necesitas código adicional en tu plantilla para ayudar a los widgets a encontrar sus medios:

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

Gracias lupefiasco para esta adición.

Otros consejos

Como la solución es pirateada, creo que es más factible usar su propio widget de fecha/hora con algo de JavaScript.

Sí, terminé anulando la URL /admin/jsi18n/.

Esto es lo que agregué en mi urls.py.Asegúrate de que esté encima de la URL /admin/

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

Y aquí está la función i18n_javascript que creé.

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

Mi código principal para la versión 1.4 (algunos nuevos y otros eliminados)

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

Me encuentro haciendo muchas referencias a esta publicación y descubrí que el documentación define un levemente forma menos complicada de anular los widgets predeterminados.

(No es necesario anular el método __init__ de ModelForm)

Sin embargo, aún necesita conectar su JS y CSS adecuadamente como menciona Carl.

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

Referencia Tipos de campo para encontrar los campos del formulario predeterminados.

A partir de Django 1.2 RC1, si estás usando el truco del widget del selector de fecha del administrador de Django, debes agregar lo siguiente a tu plantilla, o verás la URL del ícono del calendario referenciada a través de "/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>

Complementando la respuesta de Carl Meyer, me gustaría comentar que debes colocar ese encabezado en algún bloque válido (dentro del encabezado) dentro de tu plantilla.

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

Lo siguiente también funcionará como último recurso si lo anterior falla

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

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

Igual que

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

    class Meta:
        model = Payments

pon esto en tus formularios.py from django.forms.extras.widgets import SelectDateWidget

¿Qué tal simplemente asignar una clase a su widget y luego vincular esa clase al selector de fechas de JQuery?

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

Y algo de JavaScript para la plantilla:

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

Para Django >= 2.0

Nota:Usar widgets de administración para los campos de fecha y hora no es una buena idea ya que las hojas de estilo de administración pueden entrar en conflicto con las hojas de estilo de su sitio en caso de que esté utilizando bootstrap o cualquier otro marco CSS.Si está creando su sitio con bootstrap, use mi widget bootstrap-datepicker django-bootstrap-datepicker-plus.

Paso 1: Agregar javascript-catalog URL de su proyecto (no de la aplicación) urls.py archivo.

from django.views.i18n import JavaScriptCatalog

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

Paso 2: Agregue los recursos JavaScript/CSS necesarios a su plantilla.

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

Paso 3: Utilice widgets de administración para los campos de entrada de fecha y hora en su 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,
        }

Solución actualizada y solución alternativa para Dividir fecha y hora con requerido = Falso:

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

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

Yo uso esto, es genial, pero tengo 2 problemas con la plantilla:

  1. Veo los íconos del calendario dos veces para cada plantilla archivada.
  2. Y para TimeField tengo 'Introduzca una fecha válida.'

    Here is a screenshot of the Form

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

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

En Django 10.miproyecto/urls.py:al comienzo de urlpatterns

  from django.views.i18n import JavaScriptCatalog

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

En mi plantilla.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>

Mi configuración de Django:1.11 Bootstrap:3.3.7

Como ninguna de las respuestas es completamente clara, comparto el código de mi plantilla que no presenta ningún error.

Mitad superior de la plantilla:

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

Mitad inferior:

<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 %}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top