Django过滤器ModelFormSet字段选择...与限制Formset的查询不同 [英] Django filter ModelFormSet field choices... different from limiting the Formset's queryset
问题描述
我知道有可能覆盖模型模型使用的默认查询集。这只是限制了一个表单创建的对象。
我还发现了一个Stack Overflow问题,关于过滤Django ModelForm中的ForeignKey选项,而不是ModelForm Set 和<限制Django表单集中的可用选项的href =https://stackoverflow.com/questions/1129759/limiting-available-choices-in-a-django-formset,而不是模型 FormSet。我已经在下面的代码中包含了我的版本。
我想做的是渲染一个ModelFormSet,为一个学校类('教学组'或'类'以避免冲突使用'class'关键字),其中一个字段受到查询器的限制。这是一个教师的课堂编辑表格,能够重新分配学生到不同的班级,但限于同一队列中的班级。
我的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']
我的views.py
def edit_pupils(request,teachinggroup):
theclass = TeachingGroup.objects.get(name__iexact = teachinggroup)
学生= 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] ####我也尝试过
如果request.method =='POST':
formset = PupilModelFormSet(request.POST,queryset = pupils)
如果formset.is_valid():
formset.save()
返回重定向(display_class_list,teachinggroup = teachinggroup)
else :
formset = PupilModelFormSet(queryset = pupils)
表单中的表单:
表单中的字段:
如果教学组== field.label:
field.choices = choice
返回rend er_to_response('reassign_pupils.html',locals())
正如你所看到的,我限制queryset classes_by_year的选择,这只是属于同一组的类。这个查询结果正确显示,正如您在下面的渲染页面中可以看到的,但它并不影响表单字段。
我的模板
{form for formset%}
< tr>
{%for form.visible_fields%}
< td> {#在{}中包含隐藏的字段
{%如果forloop.first%}
{%隐藏在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 =submitvalue =提交更改>< / p>
< / form>
{{choices}}<! - 包含调试 - >
页面呈现所有教学组(类)在选择小部件中可见,但标签在页面底部呈现为: c ,仅准确显示第8年的两个类别。 c 请注意,我也读过詹姆斯·班内特的帖子所以你想要一个动态表单,如如何限制django modelformset中外键字段的可用选项?,但这涉及修改forms.py中的 进一步帮助m Luke Sneeringer ,这里是我的新的forms.py条目。阅读为什么我得到一个对象不是可迭代的错误?我意识到,当我想要一个字典时,我的一些问题来自于给一个元组的field.choices方法。我使用了.queryset方法,它的工作正常: 尽可能的告诉我们,你实际上把所有的东西都放在一起,除了一个。这是最后一个链接。 你说你读过动态表单的帖子,这涉及到覆盖一个 即使 显然,这需要定义 您可能遇到的最后一个问题是,一个 I understand that it is possible to override the default queryset 'used' by the modelformset. This just limits the objects for which a form is created. I also found a Stack Overflow question about filtering ForeignKey choices in a Django ModelForm, but not a ModelForm Set and about limiting available choices in a Django formset, but not a Model FormSet. I have included my version of this code below. What I want to do is render a ModelFormSet, for a school class ('teachinggroup' or 'theclass' to avoid clashing with the 'class' keyword) with one field limited by a queryset. This is for a teacher's class-editing form, to be able to reassign pupils to a different class, but limited to classes within the same cohort. My models.py My views.py As you can see, I am limiting the choices to the queryset classes_by_year, which is only classes which belong to the same year group. This queryset comes out correctly, as you can see in the rendered page below, but it doesn't affect the form field at all. My template The page renders with all teaching groups (classes) visible in the select widget, but the tag at the bottom of the page renders as: Note that I've also read through James Bennett's post So you want a dynamic form as recommended by How can I limit the available choices for a foreign key field in a django modelformset?, but that involves modifying the Further to help from Luke Sneeringer, here is my new forms.py entry. After reading Why do I get an object is not iterable error? I realised that some of my problems came from giving a tuple to the field.choices method, when it was expecting a dictionary. I used the .queryset approach instead, and it works fine:
As best as I can tell, you've actually put all the pieces together except one. Here's the final link. You said you read the dynamic form post, which involves overriding the Even though Obviously, this requires defining the The last problem you might have is that a 这篇关于Django过滤器ModelFormSet字段选择...与限制Formset的查询不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
__ init __
方法,但是我知道如何创建ModelFormSet的唯一方法是使用modelsformset_factory,它不涉及在forms.py中定义任何类。
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
__ init __
forms.Form
子类,你没有。但是,没有任何东西阻止你有一个,那就是你可以覆盖你的选择。
modelformset_factory
不需要一个明确的 Form
class(如果没有提供的话,它会从模型中构造一个),它可以需要一个。使用表单
关键字参数:
PupilModelFormset = modelformset_factory(Pupil,form = PupilForm)
PupilForm
类。我得到你已经知道如何做的印象,但它应该是这样的:
from django import forms
class PupilForm(forms.ModelForm):
def __init __(self,* args,** kwargs):
super(PupilForm,self).__ init __(* args,** kwargs)
self.fields ['teaching_group']。选择= ______#在这里生成选项的代码
class Meta:
model = Pupil
modelformset_factory
只是接受该类,这意味着将无调用构造函数。如果你需要动态地发送一个参数,那么这样做就是使一个生成窗体类的元类,并在你的 modelformset_factory
call。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']
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())
{% 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 -->
[<TeachingGroup: Y8 82Ma2>, <TeachingGroup: Y8 82Ma3>]
, accurately showing only the two classes in Year 8.__init__
method in forms.py, and yet the only way I know how to create a ModelFormSet is with modelformset_factory, which doesn't involve defining any classes in forms.py.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
__init__
method in a forms.Form
subclass, which you don't have. But, nothing stops you from having one, and that's where you can override your choices.modelformset_factory
doesn't require an explicit Form
class (it constructs one from the model if none is provided), it can take one. Use the form
keyword argument:PupilModelFormset = modelformset_factory(Pupil, form=PupilForm)
PupilForm
class. I get the impression you already know how to do this, but it should be something like:from django import forms
class PupilForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PupilForm, self).__init__(*args, **kwargs)
self.fields['teaching_group'].choices = ______ # code to generate choices here
class Meta:
model = Pupil
modelformset_factory
just takes the class, which means that the constructor will be called with no arguments. If you need to send an argument dynamically, the way to do it is to make a metaclass that generates the form class itself, and call that metaclass in your modelformset_factory
call.