2009-11-08 13 views
17

Il caso particolare che ho è come questo:Come passare il parametro iniziale all'istanza ModelForm di django?

Ho un modello di transazione, con i campi: from, to (entrambi sono ForeignKey s per auth.User modello) e amount. Nel mio modulo, vorrei presentare i campi dell'utente 2 da compilare: amount e from (to verrà automaticamente impostato all'utente corrente in una funzione di visualizzazione).

Il widget predefinito per presentare un ForeignKey è una casella di selezione. Ma quello che voglio arrivare, è limitare le scelte solo ai membri del queryset user.peers (così le persone possono solo registrare le transazioni con i loro coetanei e non venire inondati da tutti gli utenti del sistema).

Ho provato a cambiare il ModelForm a qualcosa di simile:

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

    class Meta: 
    model = models.Transaction 

Ma sembra che devo passare il set di query di scelte per ModelChoiceField proprio qui - in cui non ho un accesso al web request.user oggetto.

Come limitare le scelte in un modulo a quelle dipendenti dall'utente?

risposta

29

utilizzare il seguente metodo (si spera è chiaro abbastanza):

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

creare moduli come questo:

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

Speranza che aiuta! Fammi sapere se hai bisogno che spieghi più in profondità.

+0

Grazie mille! Questo mi ha davvero aiutato. – kender

+4

Dall'interno della classe Form è possibile accedere all'istanza del modello tramite 'self.instance'. Ricorda che l'istanza sarà piuttosto vuota quando aggiungi/crea un nuovo oggetto. – JCotton

+2

Un po 'più semplice è la cattura di systemid come argomento regolare nel __init __() passando ** kwargs direttamente attraverso: 'def __init __ (self, systemid, * args, ** kwargs): super (BackupForm, self) .__ init __ (* args, ** kwargs) ' – JCotton

2

Nel http://www.djangobook.com/en/2.0/chapter07/, sezione Impostazione dei valori iniziali descrive come utilizzare il parametro initial al costruttore Form. Puoi anche fare cose extra nel metodo __init__ del tuo derivato Form.

+0

passare i dati iniziali impostare la casella di selezione sul valore specificato - non limitare le scelte o modificare la convalida, che otterrei con l'impostazione di QuerySet nella definizione ModelForm. – kender

+0

È possibile controllare il parametro iniziale (o qualche altro parametro) nel costruttore e impostare i limiti di conseguenza? –

6

mi sono imbattuto in questo problema così, e questa è stata la mia soluzione:

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

Far passare l'utente nella __init__ della forma, e quindi chiamare super(…). Quindi impostare self.fields['from'].queryset su user.peers