43 votes

Comment modifiez-vous le widget par défaut pour tous les champs de date Django dans un ModelForm?

Étant donné un ensemble typique de modèles:

# 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()

...

Comment peut-on modifier le widget par défaut pour tous les DateFields à une coutume MyDateWidget?

Je demande parce que je veux que ma demande de jQueryUI datepicker pour la saisie des dates.

Je l'ai considéré comme un champ personnalisé qui s'étend de django.db.modèles.DateField avec mon widget personnalisé. Est-ce la meilleure façon de mettre en œuvre ce genre de travers-le-pension changement? Cette modification exige spécifiquement l'importation spéciale MyDateField dans chaque modèle, ce qui est un travail intensif, sujets à l'erreur développeur (c'est à dire un peu de modèles.DateField volonté de passer à travers), et dans mon esprit semble comme une duplication inutile des efforts. D'autre part, je n'aime pas la modification de ce qui pourrait être considéré comme la version canonique de modèles.DateField.

Les pensées et les suggestions sont appréciées.

60voto

James Bennett Points 6318

Vous pouvez déclarer un attribut sur votre ModelForm classe, appelés formfield_callback. Ce doit être une fonction qui prend un modèle Django Field exemple comme argument, et renvoie un formulaire Field exemple pour la représenter dans la forme.

Ensuite, tout ce que vous avez à faire est de regarder pour voir si le modèle de champ transmis est une instance d' DateField et, si oui, de retour de votre champ personnalisé/widget. Si non, le modèle de champ ont une méthode nommée formfield que vous pouvez appeler à revenir à sa valeur par défaut du champ de formulaire.

Donc, quelque chose comme:

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

10voto

Soviut Points 26384

Cet article m'a aidé à de nombreuses reprises.

La viande de celui-ci implique la substitution de la ModelForm de l' __init__ méthode, puis l'appel de la super-classe' __init__ méthode, puis en ajustant les champs individuellement.

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

Cette méthode peut sembler plus compliqué que Vasil, mais il offre l'avantage supplémentaire d'être capable de remplacer n'importe quel attribut sur un terrain sans réinitialiser les autres attributs de la re-déclarer.

6voto

Vasil Points 11172

Eh bien, faire un modèle de champ juste pour le changer par défaut du widget n'est pas vraiment le point de départ évident.

Vous pouvez faire votre propre forme de widget et de remplacer le champ dans le formulaire, en précisant votre propre widget comme dans Soviut de réponse.

Il y a aussi un plus court chemin:

class ArticleForm(ModelForm):
     pub_date = DateField(widget=MyDateWidget())

     class Meta:
         model = Article

Il est un exemple de la façon d'écrire de la forme de widgets, c'est quelque part dans le système de formulaires de Django. C'est un datepicker avec 3 listes déroulantes.

Ce que j'ai l'habitude de faire quand je veux juste ajouter un peu de JavaScript à une norme HTML de l'élément d'entrée est le laisser comme ça et de le modifier par le référencement c'est l'id plus tard avec JavaScript. Vous pouvez facilement attraper la convention de nommage pour les id des champs de saisie de Django génère.

Vous pouvez également fournir de la classe du widget lorsque vous la remplacez dans le formulaire. Puis les attraper tous avec jQuery par le nom de la classe.

4voto

MarC Points 31

J'utilise JQuery. Il vous suffit de rechercher le 'id' des champs que vous souhaitez associer au sélecteur de date et de les lier avec JQuery et le format d'affichage approprié:

models.py

 class ObjectForm(ModelForm):
    class Meta:
        model = Object        
        fields = ['FieldName1','FieldName2']
 

en haut de la page, vous rendez le rendu avec votre vue:

 <head>
    <link type="text/css" href="http://stackoverflow.com/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}}
 

1voto

Carl Meyer Points 30736

Vous ne souhaitez définir un widget personnalisé, et utiliser le widget de l' intérieur des Médias la classe pour définir le JS (et le CSS?) les fichiers qui doivent être inclus dans la page pour le widget de travail. Si vous faites ce droit, vous pouvez faire votre widget complètement autonome et réutilisables. Voir django-markitup pour un exemple de le faire (il a une réutilisables widget pour le MarkItUp! universelle de balisage de l'éditeur).

Ensuite, utilisez formfield_callback (voir James Bennett de réponse) pour appliquer facilement à ce widget à tous DateField dans un formulaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X