2009-11-08 3 views
17

Le cas particulier je ressemble à ceci:Comment passer le paramètre initial à l'instance ModelForm de django?

J'ai un modèle de transaction, avec des champs: from, to (les deux sont ForeignKey s au modèle auth.User) et amount. Dans mon formulaire, je voudrais présenter les champs de l'utilisateur 2 à remplir: amount et from (to sera automatiquement défini à l'utilisateur actuel dans une fonction de vue).

Le widget par défaut pour présenter un ForeignKey est un select-box. Mais ce que je veux y arriver, c'est de limiter les choix aux membres de Qetyset user.peers seulement (ainsi les gens peuvent seulement enregistrer des transactions avec leurs pairs et ne pas être inondés avec tous les utilisateurs du système).

J'ai essayé de changer le ModelForm à quelque chose comme ceci:

class AddTransaction(forms.ModelForm): 
    from = ModelChoiceField(user.peers) 
    amount = forms.CharField(label = 'How much?') 

    class Meta: 
    model = models.Transaction 

Mais il semble que je dois passer le queryset de choix pour ModelChoiceField ici - où je n'ai pas accès à Internet request.user objet.

Comment puis-je limiter les choix dans un formulaire à ceux qui dépendent de l'utilisateur?

Répondre

29

Utilisez la méthode suivante (espérons qu'il est assez clair):

class BackupForm(ModelForm): 
    """Form for adding and editing backups.""" 

    def __init__(self, *args, **kwargs): 
     systemid = kwargs.pop('systemid') 
     super(BackupForm, self).__init__(*args, **kwargs) 
     self.fields['units'] = forms.ModelMultipleChoiceField(
       required=False, 
       queryset=Unit.objects.filter(system__id=systemid), 
       widget=forms.SelectMultiple(attrs={'title': _("Add unit")})) 

    class Meta: 
     model = Backup 
     exclude = ('system',) 

Créer des formulaires comme celui-ci:

form_backup = BackupForm(request.POST, 
         instance=Backup, 
         systemid=system.id) 
form_backup = BackupForm(initial=form_backup_defaults, 
         systemid=system.id) 

Hope that helps! Faites-moi savoir si vous avez besoin de moi pour expliquer plus en profondeur.

+0

Merci beaucoup! Cela a vraiment aidé. – kender

+4

Depuis l'intérieur de la classe Form, vous pouvez accéder à l'instance Model via 'self.instance'. Souvenez-vous que l'instance sera plutôt vide lors de l'ajout/création d'un nouvel objet. – JCotton

+2

Un peu plus simple est d'attraper systemid comme un argument normal dans votre __init __() tout en passant ** kwargs directement: 'def __init __ (self, systemid, * args, ** kwargs): super (BackupForm, self) .__ init __ (* args, ** kwargs) ' – JCotton

2

En http://www.djangobook.com/en/2.0/chapter07/, la section Définition des valeurs initiales décrit comment utiliser le paramètre initial au constructeur Form. Vous pouvez également faire des choses supplémentaires dans la méthode __init__ de votre dérivé Form.

+0

en passant les données initiales définirait ma boîte de sélection à la valeur spécifiée - ne pas limiter les choix, ou modifier la validation, que je obtiendrais avec la définition de QuerySet dans la définition ModelForm. – kender

+0

Vous pouvez inspecter le paramètre initial (ou un autre paramètre) dans votre constructeur et définir des limites en conséquence? –

6

je suis tombé sur ce problème aussi bien, et ce fut ma solution:

class ChangeEmailForm(forms.ModelForm): 
    def __init__(self, user, *args, **kwargs): 
     self.user = user 
     super(ChangeEmailForm, self).__init__(*args, **kwargs) 
     self.fields['email'].initial = user.email 

    class Meta: 
     model = User 
     fields = ('email',) 

    def save(self, commit=True): 
     self.user.email = self.cleaned_data['email'] 
     if commit: 
      self.user.save() 
     return self.user 
0

passer le utilisateur dans le __init__ de la forme, puis appelez super(…). Le passage self.fields['from'].queryset à user.peers

Questions connexes