在内联formset中使用Django FileField

时间:2017-01-11 20:06:05

标签: django forms django-forms inline-formset django-file-upload

在我的应用中上传文件时出现问题。用户提交报告并可以添加附件(通过外键关系)。我已经显示了内联表单,如果我将其留空,则可以正常工作,但是当我尝试上传文件然后提交表单时出现500错误。已制作基本报告,但内联的附件无法保存。

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

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

{% 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,并且我在传递request.FILES views.py文件。我已经以正常形式上传文件,但内联证明是麻烦。

如果您需要我澄清任何内容,请告诉我,我们非常感谢您提供帮助:)

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

使CreateView csrf免除获得追溯

它给了我一个ValueError:save()被禁止以防止由于未保存的相关对象&#39;报告而导致的数据丢失。从跟踪中我可以看到我的文件实际上是在内存中,问题在于:traceback

随着我的进步,将继续更新,似乎这种保存FK对象的方法在1.8之前完美无缺地工作,所以如果我很幸运,它可以快速修复以使对象保存正确。

1 个答案:

答案 0 :(得分:3)

我需要做的就是将我正在使用的报表的实例传递给formset,简单易用。所以在我的CreateView的post方法中,我将report_attachment_form的声明更改为report_attachment_form = ReportAttachmentFormSet(self.request.POST, self.request.FILES, instance=form.instance),我们就像金一样好。