我无法使用嵌入式表单集通过CreateView上传文件。
理想情况下,它将是多个文件,类似于它在管理页面中的行为,但是在这一点上,我试图至少建立一个文件。在以下示例中,一个Workshop应该可以有多个文件。
上传时,所有内容都会保存,当然文件除外
...
class Workshop (models.Model):
title = models.CharField(max_length=120)
created_by = models.ForeignKey(User)
slug = models.SlugField(blank=True, null=True, unique=True)
def __str__(self):
return self.title
...
def upload_workshop_file_loc(instance, filename):
slug = instance.workshop.slug
if not slug:
slug = unique_slug_generator(instance.workshop)
location = "workshop/{}/".format(slug)
return location + filename
class WorkshopFile(models.Model):
workshop = models.ForeignKey(Workshop, related_name='files', on_delete=models.CASCADE)
name = models.CharField()
file = models.FileField(
upload_to=upload_workshop_file_loc,
null=True,
validators=[FileExtensionValidator
(allowed_extensions=['pdf', 'ppt'])]
)
def __str__(self):
return str(self.file.name)
...
from django import forms
from .models import Workshop, WorkshopFile
from django.forms.models import inlineformset_factory
class AddWorkshopForm(forms.ModelForm):
class Meta:
model = Workshop
exclude = []
FileFormSet = inlineformset_factory(Workshop,
WorkshopFile,
fields=['workshop','name', 'file'],
exclude=[],
extra=1,
can_delete=True
)
最有可能是罪魁祸首
...
class AddWorkshopView(LoginRequiredMixin, CreateView):
model = Workshop
form_class = AddWorkshopForm
template_name = "modules/add-workshop.html"
success_url = "/modules/workshop-list/"
def post(self, request, *args, **kwargs):
form = AddWorkshopForm(request.POST, request.FILES)
workshop = form.save(commit=False)
workshop.save()
workshop.created_by = request.user
return redirect('modules:workshop', workshop.slug)
def get_context_data(self, **kwargs):
data = super(AddWorkshopView, self).get_context_data(**kwargs)
if self.request.POST:
data['files'] = FileFormSet(self.request.POST)
else:
data['files'] = FileFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
files = context['files']
with transaction.atomic():
form.instance.created_by = self.request.user
form.instance.updated_by = self.request.user
self.object = form.save()
if files.is_valid():
files.instance = self.object
files.save()
return super(AddWorkshopView, self).form_valid(form)
...
...
<div>
<form method="post" action='' enctype='multipart/form-data'>
{% csrf_token %}
{{ form | crispy }}
<hr/>
<div>
{{ files | crispy }}
</div>
<input type="submit" class="btn btn-primary btn-md float-left" value="Save" />
</form>
</div>
...
答案 0 :(得分:0)
您不应覆盖post
方法-它在幕后调用form_valid
,因此实际上并没有处理表单。另一件事是您的FileFormSet
没有得到request.FILES
-这就是文件格式不对其进行处理的原因。
views.py:
class AddWorkshopView(LoginRequiredMixin, CreateView):
model = Workshop
form_class = AddWorkshopForm
template_name = "modules/add-workshop.html"
success_url = "/modules/workshop-list/"
def get_context_data(self, **kwargs):
data = super(AddWorkshopView, self).get_context_data(**kwargs)
if self.request.POST:
data['files'] = FileFormSet(self.request.POST, self.request.FILES)
else:
data['files'] = FileFormSet()
return data
def form_valid(self, form):
context = self.get_context_data()
files = context['files']
with transaction.atomic():
form.instance.created_by = self.request.user
form.instance.updated_by = self.request.user
self.object = form.save()
if files.is_valid():
files.instance = self.object
files.save()
return super(AddWorkshopView, self).form_valid(form)
答案 1 :(得分:0)
在我的情况下,将图像通过CreateView上载到s3,并且不带Formset。我希望这会对寻找这种情况的人有所帮助。
from bootstrap_modal_forms.generic import (BSModalCreateView)
from vcweb.settings import base
from .forms import InputForm
from utils import upload_to_s3 #global method for upload files to s3
from datetime import datetime
from django.utils.timezone import get_current_timezone
curdatetime = datetime.now(tz=get_current_timezone())
curdatetime=(str(curdatetime)).replace('-','_').replace('+','_').replace('.','_')
curdatetime=curdatetime.replace(':','_').replace(' ','_')
class InputCreateView(BSModalCreateView):
model = Input_Product
form_class = InputForm
template_name = 'inputs/create_product.html'
success_message = 'Success: Input Product is created.'
success_url = reverse_lazy('input_product_list')
def form_valid(self, form):
form.instance.created_by = self.request.user
form.instance.updated_by = self.request.user
# get the image by using request.FILES.get
filepath = self.request.FILES.get('product_Image', False)
user_id = self.request.user.id
#generate filename along with datetime string
key = base.INPUT_PRODUCT_IMAGE_FOLDER+'/images/' + str(user_id) + '/productimages/' + curdatetime + '.png'
if filepath == False:
print(filepath)
else: #if file exists send the those file and s3 details to upload_to_s3 to upload the data into s3
s3status = upload_to_s3(base.S3_KEY, base.S3_SECRET, filepath, base.S3_BUCKET, key, callback=None, md5=None,
reduced_redundancy=False, content_type=None)
# after upload the image, set the filepath value to column(file or image field variable)
form.instance.product_Image=key
return super().form_valid(form)
创建utils.py文件并声明upload_to_s3方法
import os
import boot
from boto.s3.key import Key
def upload_to_s3(aws_access_key_id, aws_secret_access_key, file, bucket, key,
callback=None, md5=None,
reduced_redundancy=False, content_type=None):
try:
size = os.fstat(file.fileno()).st_size
except:
# Not all file objects implement fileno(),
# so we fall back on this
file.seek(0, os.SEEK_END)
size = file.tell()
conn = boto.connect_s3(aws_access_key_id, aws_secret_access_key)
bucket = conn.get_bucket(bucket, validate=True)
k = Key(bucket)
k.key = key
if content_type:
k.set_metadata('Content-Type', content_type)
sent = k.set_contents_from_file(file, cb=callback, md5=md5,
reduced_redundancy=reduced_redundancy, rewind=True)
# Rewind for later use
file.seek(0)
if sent == size:
return True
return False