可以用FileFields预填充Django表单集吗?

oxf4rvwz  于 2023-03-04  发布在  Go
关注(0)|答案(1)|浏览(117)

我正在表单上创建附件。多个。一切都很好。问题是...我想在更新表单上"获取"这些附件,以便在表单被批准时显示并删除它们。这被证明是具有挑战性的。在某些情况下,我通过使用字典来获取所需的数据作为初始数据来预填充表单。除了Django引用的FileFields或FieldFile之外,所有的都按预期工作。我读过一些类似的SO文章...但是没有任何帮助。我理解安全问题,我不想"强制"上传。我只想获取附件名称并将其复制到另一个模型中。我的表单提交了,但是附件没有被处理。
这是我的密码...
超文本标记语言...

<form method="POST" enctype="multipart/form-data" id="forms">

    {{ procedure_attachment_form.management_form }}

    {{ procedure_attachment_form.non_form_errors }}

    {% for fileform in procedure_attachment_form.forms %}

    {{ fileform.id }}

      <div class="inline {{ procedure_attachment_form.prefix }}">

          {{ fileform.attachments }}

            {% if procedure_attachment_form.non_form_errors %}

              <h3 class="spacer174">
                {{ procedure_attachment_form.non_form_errors }}
              </h3>

            {% endif %}

            {% if fileform.attachments.errors %}

              <h3 class="spacer174">
                {{ fileform.attachments.errors }}
              </h3>

            {% endif %}

          {{ fileform.procedure.as_hidden }}

          </div>

    {% endfor %}

我的表格...

class UpdateProcedureFilesForm(forms.ModelForm):

class Meta:
    model = UpdateProcedureFiles
    fields = ['attachments']
    widgets = {
        'attachments': ClearableFileInput(attrs={'multiple': True}),
    }

我的视图(创建视图)

class UpdateProcedureView(LoginRequiredMixin,CreateView):
    model = UpdateProcedure
    form_class = UpdateProcedureForm
    template_name = 'update_procedure.html'

def get(self, request, *args, **kwargs):
    self.object = self.get_object()
    context = self.get_context_data()
    form_class = self.get_form_class()
    form = self.get_form(form_class)

    dropdown = self.kwargs["pk"]
    attachments = ProcedureFiles.objects.filter(procedure_id=dropdown)

    attachment_listofdicts = []
    for attachment in attachments:
        attachment_dict = model_to_dict(attachment)
        del attachment_dict['id']
        del attachment_dict['procedure']
        del attachment_dict['archive_procedure']
        del attachment_dict['new_procedure']
        del attachment_dict['update_procedure']
        print(attachment_dict)
        attachment_listofdicts.append(attachment_dict)

    UpdateProcedureFileFormSet = inlineformset_factory(UpdateProcedure,
                                                       UpdateProcedureFiles,
                                                       form=UpdateProcedureFilesForm,
                                                       extra=len(attachment_listofdicts),
                                                       can_order=True,
                                                       min_num=0,
                                                       validate_min=True)

    procedure_attachment_form = UpdateProcedureFileFormSet(initial=attachment_listofdicts)
    # print(procedure_attachment_form)

    return self.render_to_response(
        self.get_context_data(
            form=form,
            procedure_attachment_form=procedure_attachment_form,
        )
    )

def get_object(self, queryset=None):
    return get_object_or_404(Procedure, id=self.kwargs['pk'])

def get_initial(self):
    initial = super(UpdateProcedureView, self).get_initial()
    procedure = Procedure.objects.get(pk=self.kwargs["pk"])
    initial = procedure.__dict__.copy()
    department = self.request.user.userprofile.department_access.all()

    initial.update({
                      "name": procedure.name,  
    })

    if procedure.department in self.request.user.userprofile.department_access.all() and procedure.access_level == "Default" :
        return initial
    else:
        raise Http404

def get_context_data(self, **kwargs):
    context = super(UpdateProcedureView, self).get_context_data(**kwargs)
    pk=self.kwargs["pk"]
    if self.request.POST:
        context["attachments"] = UpdateProcedureFileFormSet(self.request.POST,self.request.FILES)
    else:
        context["attachments"] = UpdateProcedureFileFormSet()
    return context

def form_valid(self, form, procedure_attachment_form):
    self.object = form.save()
    procedure_attachment_form.instance = self.object

    instance = form.save()
    return super(UpdateProcedureView, self).form_valid(form)

def form_invalid(self, form, procedure_attachment_form):
    return self.render_to_response(
        self.get_context_data(form=form,
                              procedure_attachment_form=procedure_attachment_form,
                              ))

def post(self, request, *args, **kwargs):
    print(request.POST)
    if "cancel" in request.POST:
        return HttpResponseRedirect(reverse('Procedures:procedure_main_menu'))
    else:
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        user = request.user
        userprofile = request.user
        procedure_attachment_form = UpdateProcedureFileFormSet(self.request.POST,self.request.FILES)
        files = request.FILES.getlist('attachments') #field name in model
        if (form.is_valid() and procedure_attachment_form.is_valid()):
            procedure_instance = form.save(commit=False)
            procedure_instance.user = user
            procedure_instance.save()
            for f in files:
                file_instance = UpdateProcedureFiles(attachments=f, update_procedure=procedure_instance)
                file_instance.save()
            return self.form_valid(form, procedure_attachment_form)
        else:
            return self.form_invalid(form, procedure_attachment_form)

同样,这一切都是可行的。唯一的例外是当涉及到文件字段时...那么什么也没有。

hyrbngr7

hyrbngr71#

一位来自Facebook群组的好心人Matt霍斯金斯向我提供了这个解释,经过3天的研究,我倾向于相信他。以一个基本的前提结束这个解释,那就是如果可能的话,这是不容易做到的。接下来是一个不同的方法。下面是他更有说服力的总结.... a.啊,我想我理解这个问题。这根本不是表单集的问题。关键是你试图为表单上的文件字段设置一个初始值,而表单并没有绑定到一个示例。HTML文件输入不能接受初始值(这不是django的东西,这只是HTML/浏览器的工作原理),所以当django呈现一个文件域小部件时,即使底层数据有初始值,也不会有初始值。django如何编辑带有文件字段的模型示例是,如果用户在表单上选择一个文件并提交,那么浏览器将提交该文件作为字段的值,django将更新示例上的字段,但是,如果用户没有在表单上选择文件,则浏览器根本不会提交该字段(这并不是说它会为字段提交空值,request.FILES中没有字段的条目),当这种情况发生时,django不会更新示例中的字段ClearableFileInput小部件向纯HTML文件输入添加额外的HTML复选框字段,以允许清除要请求的现有值,并将显示任何现有值的名称,但是文件输入本身仍然不能具有存储在其上的任何初始值。因此,当用户使用ClearableFileInput小部件提交表单而不选择新文件时,request.FILES中不会出现该字段(clear checkbox字段的值会被提交,但这仅仅是告诉django是否要清除示例上的file字段).所以如果你的内联表单集是用实际的示例而不是初始化的来预填充的,那么它就可以工作,但是因为您试图基于现有数据创建一组新的示例,而现有数据仅由HTML表单提供,并且因为html输入文件字段不能有初始值,所以对于用户未接触的字段,您将一无所获(事实上,你可以看到ClearableFileInput小部件显示的文件值从初始值中提取出来,这是一种误导--这些值不是由表单提交的)。希望这是有意义的......我'我很快会再写一些感想🙂

相关问题