仅在 django 中创建基于更新类的视图时,为我的文件上传使用表单集不起作用
Posted
技术标签:
【中文标题】仅在 django 中创建基于更新类的视图时,为我的文件上传使用表单集不起作用【英文标题】:Using formsets for my fileupload does not work when doing an update class based view only on create in django 【发布时间】:2021-03-14 00:34:54 【问题描述】:我在网上使用了尽可能多的示例,试图让我的两个简单模型能够进行内联表单集,从而允许我将许多文件添加到技术图纸中。 这不起作用,我只能为 Create 添加一个文件,而更新只更新 Technical_Entry 模型,而不是一个文件......这本身就很有趣。创建时的 UI 显示一个添加文件的位置,然后保存整个记录及其子记录。这样可行。 更新后,UI 显示了之前保存的文件..(太棒了!),但随后又有两个“选择文件”插槽(随机?),当单击保存时,向其中添加文件不会执行任何操作。它不会删除之前在创建中添加的文件,但它也 不保存添加到现在三个插槽(一个已使用,两个空闲)的新文件。所以由于某种原因更新不适用于文件。
class Technical_Entry(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
ema = models.ForeignKey(EMA, on_delete=models.CASCADE)
system = models.ForeignKey('System', on_delete=models.CASCADE) # are SYSTEMS RELATED TO SUBSYSTEMS OR JUST TWO GROUPS?
sub_system = models.ForeignKey(SubSystem, on_delete=models.CASCADE)
drawing_number = models.CharField(max_length=200)
drawing_title = models.CharField(max_length=255)
engineer = models.CharField(max_length=200)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
date_drawn = models.DateField()
ab = models.BooleanField()
class Technical_Entry_Files(models.Model):
tech_entry = models.ForeignKey(Technical_Entry, on_delete=models.CASCADE)
file = models.FileField(upload_to='techdb/files/')
def __str__(self):
return self.tech_entry.drawing_number
使用表单集上传。虽然页面“显示”大部分正确,但它并没有在 Technical_Entry_Files 模型中创建记录。
相关forms.py:
class FileUploadForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(FileUploadForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-4'
self.helper.field_class = 'col-lg-8'
class Meta:
model = Technical_Entry_Files
fields = ('file',)
TechFileFormSet = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=1, max_num=15)
class Technical_EntryForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Technical_EntryForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-4'
self.helper.field_class = 'col-lg-8'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = Technical_Entry
fields = ('category', 'ema', 'system', 'sub_system', 'drawing_number', 'drawing_title', 'engineer', 'vendor', 'date_drawn', 'ab')
widgets =
'date_drawn':DateInput(attrs=
'class':'datepicker form-control',
'id' : 'datetimepicker2',
'tabindex' : '1',
'placeholder' : 'MM/DD/YYYY hh:mm',
'autocomplete':'off',
, format='%m/%d/%Y'),
'system' : Select(attrs='tabindex':'2'),
相关views.py:
class TechEntryCreateView(LoginRequiredMixin, CreateView):
print ("we are here")
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
print(template_name)
success_url = '/techentry_add'
def get_context_data(self, **kwargs):
data = super(TechEntryCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['file_upload'] = TechFileFormSet(self.request.POST, self.request.FILES)
else:
data['file_upload'] = TechFileFormSet()
return data
def form_valid(self, form):
context =self.get_context_data()
file_upload = context['file_upload']
with transaction.atomic():
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
return super(TechEntryCreateView, self).form_valid(form)
class TechEntryUpdateView(LoginRequiredMixin, UpdateView):
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
success_url = '/'
def get_context_data(self, **kwargs):
context = super(TechEntryUpdateView, self).get_context_data(**kwargs)
if self.request.POST:
context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
else:
context["file_upload"] = TechFileFormSet(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
file_upload = context["file_upload"]
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
return super(TechEntryUpdateView, self).form_valid(form)
以及 tech_entry_form.html:
% extends 'base.html' %
% load static %
% block page-js %
<script>
$('.link-formset').formset(
addText: 'add file',
deleteText: 'remove',
);
</script>
% endblock %
% block content %
<main role="main" class="container">
<div class="starter-template">
<h1>New Tech Entry</h1>
</div>
<h2> Details of Technical Entry </h2>
<div class="row">
<div class="col-sm">
<form action="" method="post" enctype="multipart/form-data">% csrf_token %
form.as_p
<h2> Files </h2>
file_upload.management_form
% for upload_form in file_upload.forms %
<div class="link-formset">
upload_form.file
</div>
% endfor %
<input type="submit" value="Save"/><a href="% url 'tech_database:index' %">back to the list</a>
</form>
</div>
</div>
</div>
</main><!-- /.container -->
% endblock %
以及编辑时 UI 的样子...
【问题讨论】:
你在创作的时候能上传多张图片吗? 不,这根本不起作用。因此,专注于进行创建并仅进行一次上传即可工作,确实如此!然后认为第二步是能够在更新视图上编辑该上传以工作,这就是在这里不起作用的。那么接下来...第 3 步是让我上传许多图像,然后最终删除/更改未来的多个图像。 【参考方案1】:class TechEntryUpdateView(LoginRequiredMixin, UpdateView):
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
success_url = '/'
#log_entry_class = Technical_EntryForm(Technical_Entry) #removed
def get_context_data(self, **kwargs):
context = super(TechEntryUpdateView, self).get_context_data(**kwargs)
#self.object = self.get_object() #removed
if self.request.POST:
context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
else:
context["file_upload"] = TechFileFormSet(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
file_upload = context["file_upload"]
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
#return super().form_valid(form)
return super(TechEntryUpdateView, self).form_valid(form) #replaced old one
更新 1.为了在创建时能够添加多个文件,
TechFileFormSet = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=4, max_num=4)
# note I changed to extra=4, if you always want to have only 4 files, then also change to max_num=4
2. 更新时,修改视图后还是不能更新是因为你没有传递 hidden fields
。您没有传递文件的id
s,因此,您的表单集没有传递.is_valid()
,因此没有更新。添加关于隐藏字段的 for 循环,如下所示。
file_upload.management_form
% for upload_form in file_upload.forms %
% for hidden in upload_form.hidden_fields %
hidden
% endfor %
<div class="link-formset">
upload_form.file
</div>
% endfor %
#注意我添加的for loop
hidden fields
。
【讨论】:
逐字记录(编辑过的 OP)。还是没有骰子。也发布了编辑时 UI 的屏幕截图... 感谢截图。所以,1)它看起来像实例工作,因为你看到创建的文件。 2) 什么东西不工作? 创造作品!我也可以发布一个屏幕截图。此处发布的是更新视图...它会从数据库中填写应有的字段,如果我更改字段,它确实会尊重该更改并反映在数据库中。它知道它正在尝试编辑文件......有一个“当前”指向我在创建时上传的文件......但是如果我去更改文件,那实际上并没有在数据库中更改或没有磁盘上的新文件。 另外......我不想改变太多,就像删除和添加更多(任意数量)所以文件部分的编辑不起作用,即使它确实有效让我改变......它仍然不是我需要的最终化身。 只是为了确定,您更改了 updateview 的最后一行,对吧?以上是关于仅在 django 中创建基于更新类的视图时,为我的文件上传使用表单集不起作用的主要内容,如果未能解决你的问题,请参考以下文章