Django définit les valeurs de formulaire par défaut

241

J'ai un modèle comme suit:

class TankJournal(models.Model):
    user = models.ForeignKey(User)
    tank = models.ForeignKey(TankProfile)
    ts = models.IntegerField(max_length=15)
    title = models.CharField(max_length=50)
    body = models.TextField()

J'ai également un formulaire modèle pour le modèle ci-dessus comme suit:

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput()) 

    class Meta:
        model = TankJournal
        exclude = ('user','ts')

Je veux savoir comment définir la valeur par défaut pour ce champ caché du réservoir. Voici ma fonction pour afficher / enregistrer le formulaire jusqu'à présent:

def addJournal(request, id=0):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/')

    # checking if they own the tank
    from django.contrib.auth.models import User
    user = User.objects.get(pk=request.session['id'])

    if request.method == 'POST':
        form = JournalForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)

            # setting the user and ts
            from time import time
            obj.ts = int(time())
            obj.user = user

            obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])

            # saving the test
            obj.save()

    else:
        form = JournalForm()

    try:
        tank = TankProfile.objects.get(user=user, id=id)
    except TankProfile.DoesNotExist:
        return HttpResponseRedirect('/error/')
Mike
la source

Réponses:

402

Vous pouvez utiliser l' initiale qui est expliquée ici

Vous avez deux options pour remplir la valeur lors de l'appel du constructeur de formulaire:

form = JournalForm(initial={'tank': 123})

ou définissez la valeur dans la définition du formulaire:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 
Sergey Golovchenko
la source
Et comment cette variable est-elle initialtransmise au formulaire réel? Dans le modèle de formulaire actuel, devons-nous écrire comme paramètre / argument?
mgPePe
2
@bharal C'est magique. ;-) (Ou plutôt, les constructeurs de formulaires Django comprennent la variable spéciale "initiale" et parcourent son contenu sans que vous ayez besoin de faire quoi que ce soit de plus). Personnellement, je préfère spécifier des valeurs par défaut dans la définition du formulaire et n'utiliser le mécanisme initial = ... que si la valeur par défaut souhaitée est une valeur dynamique (par exemple quelque chose entré par un utilisateur, ou basé sur son identifiant, sa situation géographique, etc.)
Richard J Foster
66
initial n'est pas par défaut. La valeur initiale ne s'applique pas si le formulaire a été lié :(.
clime
4
Commenter ici pour mentionner un autre cas d'utilisation où cette solution de paramètre initial vous aidera: lors de l'envoi d'un lien d'inscription à quelqu'un si vous souhaitez préremplir l'e-mail / id ou tout autre identifiant sur le formulaire d'inscription, alors dans ce cas, vous ne pouvez pas l'écrire dans le modèle lui-même comme dynamique, vous devez plutôt appeler le constructeur avec le paramètre initial comme mentionné par @ umnik700. Fonctionne très bien!
Keshav Agrawal
1
@Phlip: ne remplacez pas View.get_formpour définir les données initiales. Tout CBV avec un FormMixin (essentiellement tous les CBV qui créent ou modifient des données) peut soit utiliser une initialvariable au niveau de la classe (pour les valeurs par défaut immuables) ou vous pouvez remplacer FormMixin.get_initial()pour renvoyer un dict des valeurs initiales à transmettre au constructeur du formulaire (pour les valeurs par défaut dynamiques .)
GDorn
29

Autre solution: définir l'initiale après la création du formulaire:

form.fields['tank'].initial = 123
Andreas Zwerger
la source
Cela fonctionne pour mon besoin, n'initiez qu'un seul champ du formulaire. Merci.
bl4ckb1rd
11

J'avais cette autre solution (je la poste au cas où quelqu'un d'autre comme moi utilise la méthode suivante du modèle):

class onlyUserIsActiveField(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
        self.fields['is_active'].initial = False

    class Meta:
        model = User
        fields = ['is_active']
        labels = {'is_active': 'Is Active'}
        widgets = {
            'is_active': forms.CheckboxInput( attrs={
                            'class':          'form-control bootstrap-switch',
                            'data-size':      'mini',
                            'data-on-color':  'success',
                            'data-on-text':   'Active',
                            'data-off-color': 'danger',
                            'data-off-text':  'Inactive',
                            'name':           'is_active',

            })
        }

L'initiale est définie sur la __init__fonction commeself.fields['is_active'].initial = False

Izuzvo
la source
0

J'espère que cela pourra vous aider:

form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id
Code47
la source
0

Comme expliqué dans les documents Django , ce initialn'est pas le cas default.

  • La valeur initiale d'un champ est destinée à être affichée dans un HTML. Mais si l'utilisateur supprime cette valeur et renvoie finalement une valeur vide pour ce champ, la initialvaleur est perdue. Vous n'obtenez donc pas ce qui est attendu d'un comportement par défaut .

  • Le comportement par défaut est: la valeur que prendra le processus de validation si l' dataargument ne contient aucune valeur pour le champ.

Pour mettre en œuvre cela, un moyen simple consiste à combiner initialet clean_<field>():

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

    (...)

    def clean_tank(self):
        if not self['tank'].html_name in self.data:
            return self.fields['tank'].initial
        return self.cleaned_data['tank']
Timothé Delion
la source