jquery - fields - ¿Cómo se cambia el widget predeterminado para todos los campos de fecha de Django en un ModelForm?
django widget render (6)
¿Desea definir un widget personalizado y usar la clase de medios interna del widget para definir los archivos JS (y CSS?) Que deben incluirse en la página para que funcione el widget. Si haces esto bien, puedes hacer que tu widget sea completamente autónomo y reutilizable. Consulte django-markitup para ver un ejemplo de django-markitup hacerlo (tiene un widget reutilizable para el editor de marcado MarkItUp! Universal ).
Luego usa formfield_callback (mira la respuesta de James Bennett) para aplicar fácilmente ese widget a todos los campos de DateField en un formulario.
Dado un conjunto de modelos típicos:
# Application A
from django.db import models
class TypicalModelA(models.Model):
the_date = models.DateField()
# Application B
from django.db import models
class TypicalModelB(models.Model):
another_date = models.DateField()
...
¿Cómo podría uno cambiar el widget predeterminado para todos los DateFields a un MyDateWidget personalizado?
Pregunto porque quiero que mi aplicación tenga un jQueryUI datepicker para ingresar las fechas.
He considerado un campo personalizado que amplía django.db.models.DateField con mi widget personalizado. ¿Es esta la mejor manera de implementar este tipo de cambio general? Tal cambio requerirá la importación específica de un MyDateField especial en cada modelo, que requiere mucha mano de obra, es propenso a errores del desarrollador (es decir, algunos modelos.DateField se realizará), y en mi opinión parece una innecesaria duplicación de esfuerzos. Por otro lado, no me gusta modificar lo que podría considerarse la versión canónica de los modelos.DateField.
Pensamientos y aportes son apreciados.
Algunos podrían fruncir el ceño ante esto, pero para reemplazar el selector de fecha con su widget personalizado, crearía una aplicación de monopatch para su proyecto y repararía el propio Django en tiempo de ejecución. El beneficio de esto es que las aplicaciones de terceros también se verán afectadas y, por lo tanto, presentarán una interfaz uniforme para el usuario final sin tener que modificar el código de terceros:
from django.forms.widgets import DateInput , DateTimeInput, TimeInput
from FOO.widgets import MyjQueryWidget
# be nice and tell you are patching
logger.info("Patching ''DateInput.widget = MyjQueryWidget'': Replaces django DateInput to use my new super ''MyjQueryWidget''")
# be nicer and confirm signature of code we are patching and warn if it has changed - uncomment below to get the current hash fingerprint
# raise Exception(hashlib.md5(inspect.getsource(DateInput.widget)).hexdigest()) # uncommet to find latest hash
if not ''<enter hexdigest fingerprint here>'' == /
hashlib.md5(inspect.getsource(DateInput.widget)).hexdigest():
logger.warn("md5 signature of ''DateInput.widget'' does not match Django 1.5. There is a slight chance patch "
"might be broken so please compare and update this monkeypatch.")
# be nicest and also update __doc__
DateInput.__doc__ = "*Monkeypatched by <app name>*: Replaced django DateInput.widget with my new super ''MyjQueryWidget''" + DateInput.__doc__
DateInput.widget = MyjQueryWidget
Lo anterior está inspirado en mi html5monkeypatch que uso como parte de mis proyectos, eche un vistazo a patch_widgets.py y patch_fields.py .
Bueno, crear un campo de modelo personalizado solo para cambiar su widget de formulario predeterminado no es realmente el lugar obvio para comenzar.
Puede hacer su propio widget de formulario y anular el campo en el formulario, especificando su propio widget como en la respuesta de Soviut.
También hay una manera más corta:
class ArticleForm(ModelForm):
pub_date = DateField(widget=MyDateWidget())
class Meta:
model = Article
Hay un ejemplo de cómo escribir widgets de formulario, está en algún lugar del paquete de formularios de Django. Es un datepicker con 3 desplegables.
Lo que suelo hacer cuando solo quiero agregar algo de JavaScript a un elemento de entrada HTML estándar es dejarlo tal como está y modificarlo haciendo referencia a su id posterior con JavaScript. Puede capturar fácilmente la convención de nomenclatura para los ids de los campos de entrada que genera Django.
También puede proporcionar la clase para el widget cuando lo reemplaza en el formulario. Luego, tómalos todos con jQuery por el nombre de la clase.
Puede declarar un atributo en su clase ModelForm
, llamado formfield_callback
. Esta debería ser una función que toma una instancia de Field
modelo de Django como argumento y devuelve una instancia de Field
formulario para representarla en el formulario.
Luego, todo lo que tiene que hacer es ver si el campo modelo pasado es una instancia de DateField
y, si es así, devolver su campo / widget personalizado. De lo contrario, el campo modelo tendrá un método llamado formfield
que puede llamar para devolver su campo de formulario predeterminado.
Entonces, algo como:
def make_custom_datefield(f):
if isinstance(f, models.DateField):
# return form field with your custom widget here...
else:
return f.formfield()
class SomeForm(forms.ModelForm)
formfield_callback = make_custom_datefield
class Meta:
# normal modelform stuff here...
Yo uso JQuery. Solo tiene que buscar el ''id'' de los campos que desea asociar con el selector de fecha y vincularlos con JQuery y el formato de visualización correcto:
models.py
class ObjectForm(ModelForm):
class Meta:
model = Object
fields = [''FieldName1'',''FieldName2'']
en la parte superior de la página que renderizas con tu vista:
<head>
<link type="text/css" href="/media/css/ui-darkness/jquery-ui-1.8.2.custom.css" rel="Stylesheet" />
<script type="text/javascript" src="/media/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/media/js/jquery-ui-1.8.2.custom.min.js"></script>
</head>
<script type="text/javascript">
$(function() {
$("#id_FieldName1").datepicker({ dateFormat: ''yy-mm-dd'' });
$("#id_FieldName2").datepicker({ dateFormat: ''yy-mm-dd'' });
});
</script>
...
{{form}}
Este artículo me ha ayudado en numerosas ocasiones.
Lo principal es anular el método __init__ de __init__
, luego llamar al método '' __init__
la __init__
y luego ajustar los campos individualmente.
class PollForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PollForm, self).__init__(*args, **kwargs)
self.fields[''question''].widget = forms.Textarea()
class Meta:
model = Poll
Este método puede parecer más complicado que el de Vasil, pero ofrece el beneficio adicional de poder anular cualquier atributo en un campo sin restablecer ningún otro atributo al volver a declararlo.
ACTUALIZACIÓN: El enfoque sugerido podría generalizarse para cambiar todos los campos de fecha sin escribir estrictamente cada nombre:
from django.forms import fields as formfields
from django.contrib.admin import widgets
class PollForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PollForm, self).__init__(*args, **kwargs)
for field_name in self.fields:
field = self.fields[field_name]
if isinstance(field, formfields.DateField):
field.widget = widgets.AdminDateWidget()
class Meta:
model = Poll
Eso funcionó para mí en python3
y django 1.11