Django过滤器ModelFormSet字段选择...与限制Formset的查询不同 [英] Django filter ModelFormSet field choices... different from limiting the Formset's queryset

查看:101
本文介绍了Django过滤器ModelFormSet字段选择...与限制Formset的查询不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道有可能覆盖模型模型使用的默认查询集。这只是限制了一个表单创建的对象。



我还发现了一个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 [< TeachingGroup:Y8 82Ma2>< TeachingGroup:Y8 82Ma3> p>

请注意,我也读过詹姆斯·班内特的帖子所以你想要一个动态表单,如如何限制django modelformset中外键字段的可用选项?,但这涉及修改forms.py中的 __ init __ 方法,但是我知道如何创建ModelFormSet的唯一方法是使用modelsformset_factory,它不涉及在forms.py中定义任何类。



进一步帮助m Luke Sneeringer ,这里是我的新的forms.py条目。阅读为什么我得到一个对象不是可迭代的错误?我意识到,当我想要一个字典时,我的一些问题来自于给一个元组的field.choices方法。我使用了.queryset方法,它的工作正常:

  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。


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

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']

My 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())

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

{% 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 -->

The page renders with all teaching groups (classes) visible in the select widget, but the tag at the bottom of the page renders as: [<TeachingGroup: Y8 82Ma2>, <TeachingGroup: Y8 82Ma3>], accurately showing only the two classes in Year 8.

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 __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.

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:

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

解决方案

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 __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.

Even though 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)

Obviously, this requires defining the 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

The last problem you might have is that a 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.

这篇关于Django过滤器ModelFormSet字段选择...与限制Formset的查询不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆