使用表单集将许多文件上传到记录中,效果不佳
Using formsets to upload many files to a record, it isn't quite working
我在网上使用了尽可能多的示例,试图拼凑出我的两个简单模型:
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
使用表单集上传。虽然页面 'displays' 大部分是正确的,但它并没有在 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)
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 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)
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)
# entry = context['object']
# context['entry_id'] = entry.id
# theEntry = Technical_Entry.objects.get(pk=entry.id)
# entry_form = Technical_EntryForm(instance=theEntry)
# context['entry_form'] = entry_form
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)
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)
和 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 %}
它会保存条目但不会保存上传的文件,而且我也没有看到任何错误。
没有 techdb/files 文件夹(也许我必须创建它?)但它肯定不会在任何地方失败...创建 Technical_Entry 记录,而不是 Technical_Entry_Files记录也没有在磁盘上添加任何东西。
此外,这真的是最大的一块......它只允许我上传一个文件,即使表格应该允许多个文件到一个技术条目? (也许我需要踢一些 java 脚本)。
我发现的所有示例要么不使用基于模型的表单,要么不使用基于 class 的视图,要么只是看似矫枉过正。我只需要这些简单的模型让我上传很多文件到一个技术条目。我以为我已经很接近了,但担心我离让它工作还差得很远:/
1. 我注意到一件事是你的 <form>
没有
<form action="" method="post" enctype="multipart/form-data">
这里 1 说:
No characters are encoded. This value is required when you are using forms that have a file upload control
2. 似乎缺少的另一件事是:request.FILES
data['file_upload'] = TechFileFormSet(self.request.POST, self.request.FILES)
不确定以上是否是您应该如何纳入您的观点。
以下内容来自文档:about inlineformset 基于函数的视图。
if request.method == 'POST':
formset = ArticleFormSet(request.POST, request.FILES)
文档的另一部分:about File Uploads 说:
When Django handles a file upload, the file data ends up placed in request.FILES
我在网上使用了尽可能多的示例,试图拼凑出我的两个简单模型:
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
使用表单集上传。虽然页面 'displays' 大部分是正确的,但它并没有在 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)
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 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)
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)
# entry = context['object']
# context['entry_id'] = entry.id
# theEntry = Technical_Entry.objects.get(pk=entry.id)
# entry_form = Technical_EntryForm(instance=theEntry)
# context['entry_form'] = entry_form
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)
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)
和 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 %}
它会保存条目但不会保存上传的文件,而且我也没有看到任何错误。
没有 techdb/files 文件夹(也许我必须创建它?)但它肯定不会在任何地方失败...创建 Technical_Entry 记录,而不是 Technical_Entry_Files记录也没有在磁盘上添加任何东西。
此外,这真的是最大的一块......它只允许我上传一个文件,即使表格应该允许多个文件到一个技术条目? (也许我需要踢一些 java 脚本)。
我发现的所有示例要么不使用基于模型的表单,要么不使用基于 class 的视图,要么只是看似矫枉过正。我只需要这些简单的模型让我上传很多文件到一个技术条目。我以为我已经很接近了,但担心我离让它工作还差得很远:/
1. 我注意到一件事是你的 <form>
没有
<form action="" method="post" enctype="multipart/form-data">
这里 1 说:
No characters are encoded. This value is required when you are using forms that have a file upload control
2. 似乎缺少的另一件事是:request.FILES
data['file_upload'] = TechFileFormSet(self.request.POST, self.request.FILES)
不确定以上是否是您应该如何纳入您的观点。
以下内容来自文档:about inlineformset 基于函数的视图。
if request.method == 'POST':
formset = ArticleFormSet(request.POST, request.FILES)
文档的另一部分:about File Uploads 说:
When Django handles a file upload, the file data ends up placed in request.FILES