Capisco che sia possibile override the default queryset 'used' by the modelformset. Questo limita solo gli oggetti per i quali viene creato un modulo.Filtro Django ModelForm Imposta le scelte di campo ... diverso dalla limitazione della queryset di Formset
Ho anche trovato una domanda Stack Overflow su filtering ForeignKey choices in a Django ModelForm, ma non un ModelForm Set e circa limiting available choices in a Django formset, ma non un modello FormSet. Ho incluso la mia versione di questo codice qui sotto.
Quello che voglio fare è rendere un ModelFormSet, per una classe scolastica ('teachinggroup' o 'theclass' per evitare lo scontro con la parola chiave 'class') con un campo limitato da un queryset. Questo è per il modulo di modifica della classe di un insegnante, per essere in grado di riassegnare gli studenti a una classe diversa, ma limitato a classi all'interno della stessa coorte.
mio models.py
class YearGroup(models.Model):
intake_year = models.IntegerField(unique=True)
year_group = models.IntegerField(unique=True, default=7)
def __unicode__(self):
return u'%s (%s intake)' % (self.year_group, self.intake_year)
class Meta:
ordering = ['year_group']
class TeachingGroup(models.Model):
year = models.ForeignKey(YearGroup)
teachers = models.ManyToManyField(Teacher)
name = models.CharField(max_length=10)
targetlevel = models.IntegerField()
def __unicode__(self):
return u'Y%s %s' % (self.year.year_group, self.name)
class Meta:
ordering = ['year', 'name']
mio views.py
def edit_pupils(request, teachinggroup):
theclass = TeachingGroup.objects.get(name__iexact = teachinggroup)
pupils = theclass.pupil_set.all()
PupilModelFormSet = modelformset_factory(Pupil)
classes_by_year = theclass.year.teachinggroup_set.all()
choices = [t for t in classes_by_year]
# choices = [t.name for t in classes_by_year] #### I also tried this
if request.method == 'POST':
formset = PupilModelFormSet(request.POST,queryset=pupils)
if formset.is_valid():
formset.save()
return redirect(display_class_list, teachinggroup = teachinggroup)
else:
formset = PupilModelFormSet(queryset=pupils)
for form in formset:
for field in form:
if 'Teaching group' == field.label:
field.choices = choices
return render_to_response('reassign_pupils.html', locals())
Come potete vedere, sto limitando le scelte al classes_by_year set di query, che dista solo classi che appartengono alla stessa gruppo di anni. Questo queryset viene visualizzato correttamente, come puoi vedere nella pagina di rendering qui sotto, ma non ha alcun effetto sul campo del modulo.
mio modello
{% for form in formset %}
<tr>
{% for field in form.visible_fields %}
<td> {# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
<p><span class="bigtable">{{ field }}</span>
{% if field.errors %}
<p><div class="alert-message error">
{{field.errors|striptags}}</p>
</div>
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" value="Submit changes"></p>
</form>
{{ choices }} <!-- included for debugging -->
Il rendering della pagina con tutti i gruppi insegnamento (classi) visibile nel widget di selezione, ma il tag nella parte inferiore della pagina rende come: [<TeachingGroup: Y8 82Ma2>, <TeachingGroup: Y8 82Ma3>]
, mostrando con precisione solo le due classi in anno 8.
si noti che ho letto anche attraverso il post di James Bennett So you want a dynamic form come raccomandato da How can I limit the available choices for a foreign key field in a django modelformset?, ma che comporta la modifica del metodo __init__
in forms.py, eppure l'unico modo che conosco come creare un ModelFormSet è con modelformset_factory, che doesn comportare la definizione di qualsiasi classe in forms.py.
Ulteriori informazioni su Luke Sneeringer, ecco la mia nuova entrata in forms.py. Dopo aver letto Why do I get an object is not iterable error? ho capito che alcuni dei miei problemi derivavano dal dare una tupla al metodo field.choices, quando si aspettava un dizionario. Ho usato l'approccio .queryset invece, e funziona bene:
class PupilForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PupilForm, self).__init__(*args, **kwargs)
thepupil = self.instance
classes_by_year = thepupil.teaching_group.year.teachinggroup_set.all()
self.fields['teaching_group'].queryset = classes_by_year
class Meta:
model = Pupil
Grazie per l'antipasto dettagliato, ma sto ammettendo la sconfitta nell'interpretarlo. Se provo letteralmente con '__init __ (self)' e '__init __()', ottengo 'TypeError: __init __() ottenuto un argomento di parole chiave inattese 'auto_id'', che è generato dalla fabbrica del formset. Se provo con '(self, * args, ** kwargs)' e '__init __ (* args, ** kwargs)' (sto solo pugnalando al buio), ottengo DoesNotExist, e la forma sembra non essere vincolata . Se provo con 'super (PupilForm, self.instance, self)' Ricevo l'oggetto 'AttributeError:' PupilForm 'non ha attributo' instance''. – nimasmi
Oh, non avevo capito che c'erano argomenti. La tua seconda ipotesi era giusta. Lo guarderò in modo più dettagliato e ti ricontatterò con una modifica. –
Per quanto riguarda gli argomenti, a seguito del [suddetto articolo] (http://www.b-list.org/weblog/2008/nov/09/dynamic-forms/) ho provato anche: 'def __init __ (self, pupil, * args, ** kwargs): ' ma ottenuto' __init __() richiede almeno 2 argomenti senza parole chiave (1 dato) ' – nimasmi