在嵌入式表单集中使用Django FileField [英] Using a Django FileField in an inline formset

查看:75
本文介绍了在嵌入式表单集中使用Django FileField的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将文件上传到我的应用程序时遇到问题.用户提交报告并可以添加附件(通过外键关系).我已经显示了内联表单,如果我将其保留为空白,它将可以使用,但是当我尝试上传文件然后提交表单时,出现500错误.基本报告已创建,但是内联的附件未保存.

having issues getting the file to upload in my app. A User submits a report and can add attachments (through a foreign key relationship). I've got the inline form showing up and will work if I leave it blank, but when I try to upload a file then submit the form I get a 500 error. The base report is made, but the attachment that's getting inlined doesn't get saved.

forms.py

class ReportForm(forms.ModelForm):
    accidentDate = forms.DateField(widget=SelectDateWidget(
                                   empty_label=("Choose Year",
                                                 "Choose Month",
                                                 "Choose Day"),
                                   ),
                                   label=(u'Accident Date'),
                                   initial=timezone.now())
    claimNumber = forms.CharField(max_length=50,
                                  label=(u'Claim Number'),
                                  required=True)
    damageEstimate = forms.DecimalField(max_digits=6, decimal_places=2,
                                        label=(u'Damage Estimate'))


    description = forms.CharField(widget=forms.Textarea(attrs={'rows': 5,
                                                               'cols': 80}
                                                        ),
                                  label=(u'Description'),
                                  required=True)
    drivable = forms.BooleanField(label=(u'Drivable'), 
                                  required=False)
    receivedCheck = forms.CharField(max_length=30, label=(u'Who Received Check'))
    reported = forms.BooleanField(label=(u'Reported to Insurance Company'), 
                                  required=False)
    reportedDate = forms.DateField(widget=SelectDateWidget(
                                    empty_label=("Choose Year",
                                                 "Choose Month",
                                                 "Choose Day"),
                                ),
                               initial=timezone.now(),
                               label=(u'Date Reported to Insurance'))
    repairsScheduled = forms.DateField(widget=SelectDateWidget(
                                    empty_label=("Choose Year",
                                                 "Choose Month",
                                                 "Choose Day"),
                                ),
                               initial=timezone.now(),
                               label=(u'Scheduled Repair Date'))
    repairsCompleted = forms.DateField(widget=SelectDateWidget(
                                    empty_label=("Choose Year",
                                                 "Choose Month",
                                                 "Choose Day"),
                                ),
                               initial=timezone.now(),
                               label=(u'Repair Completion Date'))
    repairsPaid = forms.BooleanField(label=(u'Repairs Paid'), 
                                  required=False)
    subrogationReceived = forms.BooleanField(label=(u'Subrogation Received'), 
                                  required=False)
    subrogationDate = forms.DateField(widget=SelectDateWidget(
                                    empty_label=("Choose Year",
                                                 "Choose Month",
                                                 "Choose Day"),
                                ),
                               initial=timezone.now(),
                               label=('Subrogation Date'))

class Meta:
    model = Report
    exclude = ('driver',)


ReportAttachmentFormSet = inlineformset_factory(Report,  # parent form
                                                    ReportAttachment,  # inline-form
                                                    fields=['title', 'attachment'], # inline-form fields
                                                    # labels for the fields
                                                    labels={
                                                        'title': (u'Attachment Name'),
                                                        'attachment': (u'File'),
                                                    },
                                                    # help texts for the fields
                                                    help_texts={
                                                        'title': None,
                                                        'attachment': None,
                                                    },
                                                    # set to false because cant' delete an non-exsitant instance
                                                    can_delete=False,
                                                    # how many inline-forms are sent to the template by default
                                                    extra=1)

相关views.py CreateView

relevant views.py CreateView

class ReportCreateView(CreateView):
    model = Report
    form_class = ReportForm
    object = None

    def get(self, request, *args, **kwargs):
        """
        Handles GET requests and instantiates blank versions of the form
        and its inline formsets.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        report_attachment_form = ReportAttachmentFormSet()
        return self.render_to_response(
                  self.get_context_data(form=form,
                                        report_attachment_form=report_attachment_form,
                                        )
                                     )

    def post(self, request, *args, **kwargs):
        """
        Handles POST requests, instantiating a form instance and its inline
        formsets with the passed POST variables and then checking them for
        validity.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        report_attachment_form = ReportAttachmentFormSet(self.request.POST, self.request.FILES)
        if form.is_valid() and report_attachment_form.is_valid():
            return self.form_valid(form, report_attachment_form)
        else:
            return self.form_invalid(form, report_attachment_form)

    def form_valid(self, form, report_attachment_form):
        """
        Called if all forms are valid. Creates Report instance along with the
        associated ReportAttachment instances then redirects to success url
        Args:
            form: Report Form
            report_attachment_form: Report attachment Form

        Returns: an HttpResponse to success url

        """
        self.object = form.save(commit=False)
        # pre-processing for Report instance here...

        self.object.driver = Profile.objects.get(user=self.request.user)
        self.object.save()

        # saving ReportAttachment Instances
        report_attachments = report_attachment_form.save(commit=False)
        for ra in report_attachments:
            #  change the ReportAttachment instance values here
            #  ra.some_field = some_value
            ra.save()

        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, report_attachment_form):
        """
        Called if a form is invalid. Re-renders the context data with the
        data-filled forms and errors.

        Args:
            form: Report Form
        report_attachment_form: Report Attachment Form
        """
        return self.render_to_response(
                 self.get_context_data(form=form,
                                       report_attachment_form=report_attachment_form
                                       )
        )

report_form.html

report_form.html

{% block body %}
<p>
<form action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <fieldset>
            {{ form.non_field_errors }}
            {% for field in form %}
            <div class="row">
                <div class="col-md-3">{% bootstrap_label field.label %}</div>
                <div class="col-md-8">{% bootstrap_field field show_label=False %}</div>
            </div>
            {% endfor %}
    </fieldset>
    <fieldset>
            <legend>Attachments</legend>
            {{ report_attachment_form.management_form }}
            {{ report_attachment_form.non_form_errors }}
                            {% for form in report_attachment_form %}
                    <div class="inline {{ report_attachment_form.prefix }}">
                    {% for field in form.visible_fields %}
                            <div class="row">
                                    <div class="col-md-3">{% bootstrap_label field.label %}</div>
                                    <div class="col-md-8">{% bootstrap_field field show_label=False %}</div>
                            </div>
                    {% endfor %}
                    </div>
            {% endfor %}
    </fieldset>
    <div class="row">
            <div class="col-md-1">
                    <input type="submit" class="btn btn-groppus-primary bordered" value="Submit" />
            </div>
    </div>
    </form>
</p>
{% endblock %}

{% block scripts %}
    <script src="{% static 'formset/jquery.formset.js' %}"></script>
    <script type="text/javascript">
            $(function() {
                    $(".inline.{{ report_attachment_form.prefix }}").formset({
                            prefix: "{{ report_attachment_form.prefix }}", // The form prefix for your django formset
                            addCssClass: "btn btn-block btn-primary bordered inline-form-add", // CSS class applied to the add link
                            deleteCssClass: "btn btn-block btn-primary bordered", // CSS class applied to the delete link
                            addText: 'Add another attachment', // Text for the add link
                            deleteText: 'Remove attachment above', // Text for the delete link
                            formCssClass: 'inline-form' // CSS class applied to each form in a formset
                    })
            });
    </script>
{% endblock %}

很难弄清楚这个问题,因为它没有给我任何形式的回溯处理,我在表单中包括了enc-type,并且在views.py文件中传递了request.FILES .我的文件上传格式正常,但事实证明内联很麻烦.

Having a hard time figuring this one out since it doesn't give me any sort of traceback to deal with, I included the enc-type in the form, and I'm passing request.FILES in the views.py file. I've got file uploads working in normal forms, but inline is proving to be trouble.

如果您需要我澄清任何内容,请告诉我,谢谢您的帮助:)

Let me know if you need me to clarify anything, any help is appreciated :)

更新:通过使用@method_decorator(csrf_exempt, name='dispatch')

这给了我一个ValueError:禁止save()以防止由于未保存的相关对象报告"而导致数据丢失.从跟踪中,我可以看到我的文件实际上正在进入内存,而问题出在这里:

which gives me a ValueError: save() prohibited to prevent data loss due to unsaved related object 'report'. From the trace I can see that my file is in fact making it into memory, and the issue is here:

随着我的前进,它将继续更新,似乎这种保存FK对象的方法在1.8之前可以正常工作,因此,如果幸运的话,这是一种使对象正确保存的快速解决方案.

Will continue updating as I progress, seems like this method of saving FK objects worked flawlessly pre-1.8 so if I'm lucky it's a quick fix to get the object to save right.

推荐答案

我要做的就是将我正在使用的报告表单的实例传递给表单集,既简单又方便.因此,在我的CreateView的post方法中,我将report_attachment_form的声明更改为report_attachment_form = ReportAttachmentFormSet(self.request.POST, self.request.FILES, instance=form.instance),我们就像黄金一样.

All I needed to do was pass the instance of the Report Form I was working with along to the formset, nice and easy. So in my CreateView's post method, I changed the declaration of report_attachment_form to report_attachment_form = ReportAttachmentFormSet(self.request.POST, self.request.FILES, instance=form.instance) and we're good as gold.

这篇关于在嵌入式表单集中使用Django FileField的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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