【问题标题】:Django: Initializing a FormSet of custom forms with instancesDjango:使用实例初始化自定义表单的 FormSet
【发布时间】:2010-12-31 19:39:43
【问题描述】:

鉴于以下模型:

class Graph(models.Model):
    owner = models.ForeignKey(User)

    def __unicode__(self):
        return u'%d' % self.id

class Point(models.Model):
    graph = models.ForeignKey(Graph) 
    date  = models.DateField(primary_key = True)
    abs   = models.FloatField(null = True)
    avg   = models.FloatField(null = True)

    def __unicode__(self):
        return u'%s' % self.date

我正在尝试创建一个用于编辑点列表的表单。 HTML 输入标签需要设置额外的属性,所以我使用以下自定义表单:

class PointForm(forms.ModelForm):
    graph = forms.ModelChoiceField(queryset = Graph.objects.all(),
                                   widget   = forms.HiddenInput())
    date  = forms.DateField(widget = forms.HiddenInput(), label = 'date')
    abs   = forms.FloatField(widget = forms.TextInput(
                                      attrs = {'class': 'abs-field'}),
                            required = False)

    class Meta:
        model  = Point
        fields = ('graph', 'date', 'abs')  # Other fields are not edited.

    def pretty_date(self):
        return self.data.strftime('%B')

此时我不知道如何将 Point 类的实例传递给 FormSet:

def edit(request):
    PointFormSet = forms.formsets.formset_factory(PointForm, extra = 0)
    if request.method == 'POST':
        return

    # Receive 3 points to edit from the database.
    graph, res = Graph.objects.get_or_create(id = 1)
    one_day    = datetime.timedelta(days = 1)
    today      = datetime.date.today()
    do_edit    = []
    for date in [today - (x * one_day) for x in range(3)]:
        point, res = Point.objects.get_or_create(graph = graph, date = date)
        do_edit.append(point)

    formset = PointFormSet(????) # How is this initialized with the points?

我发现了一个有点工作的 hack,但它在稍后尝试处理生成的 POST 数据时会导致错误:

do_edit = []
for date in [today - (x * one_day) for x in range(3)]:
    point, res    = Point.objects.get_or_create(graph = graph, date = date)
    data          = point.__dict__.copy()
    data['graph'] = graph
    do_edit.append(data)

formset = PointFormSet(initial = do_edit)

这是如何正确完成的?

作为参考,我的模板如下所示:

<form action="" method="post">
{{ formset.management_form }}
<table>
    <tbody>
    {% for form in formset.forms %}
        <tr>
            <td>{{ form.graph }} {{ form.date }} {{ form.pretty_date }}:</td>
            <td width="100%">{{ form.abs }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>
</form>

【问题讨论】:

标签: django forms instance formset


【解决方案1】:

诀窍是使用“ModelFormset”而不是仅仅使用表单集,因为它们允许使用查询集进行初始化。文档是here,您所做的是在创建模型表单集时提供表单=*,在实例化表单集时提供查询集=*。 form=* 争论没有很好的记录(不得不在代码中挖掘一下以确保它确实存在)。

def edit(request):
    PointFormSet = modelformset_factory(Point, form = PointForm)
    qset = Point.objects.all() #or however your getting your Points to modify
    formset = PointFormset(queryset = qset)
    if request.method == 'POST':
        #deal with posting the data
        formset = PointFormset(request.POST)
        if formset.is_valid():
            #if it is not valid then the "errors" will fall through and be returned
            formset.save()
        return #to your redirect

    context_dict = {'formset':formset,
                    #other context info
                    }

    return render_to_response('your_template.html', context_dict)

所以代码很容易通过。如果请求是 GET,则将实例化的表单返回给用户。如果请求是 POST 并且表单是 not .is_valid(),则错误“失败”并在同一模板中返回。如果请求是 POST 且数据有效,则保存表单集。

希望对您有所帮助。

-会

【讨论】:

  • 啊,非常感谢,效果很好。小修正:验证 POST 数据时,初始化如下所示:“PointFormset(request.POST, queryset = qset)”。否则你会得到这个错误:“这个日期的点已经存在”。
  • doh ... 很好...我忘记了在使用 model_formset 并提供数据时,您也需要提供查询集...我实际上从未使用过这个用例.
  • 能否请您更新您对文档的损坏参考,一直试图找到他们在文档中解释这一点的位置。很棒的帖子!
【解决方案2】:

如果您只想设置一个可能的值,或者可能是一个封闭的值,则可以在用户使用commit=False 将数据发布到您的服务器后设置它们

请考虑以下代码:

class UserReferralView(View):
    ReferralFormSet = modelformset_factory(ReferralCode,
                                           form=ReferralTokenForm, extra=1)

    def get(self, request):
        pass

    def post(self, request):
        referral_formset = UserUpdateView.ReferralFormSet(request.POST)

        if referral_formset.is_valid():
            instances = referral_formset.save(commit=False)
            for instance in instances:
                instance.user = request.user
                instance.save()
            return redirect(reverse('referrals.success_view'))
         else:
            return redirect(reverse('referrals.failure_view'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2013-03-12
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    相关资源
    最近更新 更多