I'm sooo close... but I don't quite see the connection from the upload view to the model. When I use the callback in the model's FileField the upload works, but I'm not sure where the actual file copy is taking place. The goal is to make sure that chunking is happening, but the file copy action seems to be hidden somewhere?
Here's what I have:
Model:
def get_media_upload_dir(instance, filename):
user_id = instance.user.id
upload_dir = "%s/%d/%s" % (settings.MEDIA_ROOT, user_id, filename)
print "Upload dir set to: %s" % upload_dir
return upload_dir
class MediaFile(models.Model):
media_file = models.FileField(upload_to=get_media_upload_dir)
download_count = models.PositiveIntegerField(default=0)
View:
def file_upload(request, course_id):
if request.method == 'POST':
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
uploaded = form.cleaned_data['file_upload']
mediaFile = MediaFile(media_file=uploaded,
owner=request.user.profile,
creator=request.user.profile)
mediaFile.save()
return HttpResponseRedirect('/course/%s/' % course_id)
else:
form = FileUploadForm()
return render_to_response('course/file_upload.html', {'form':form,'course':course}, context_instance=RequestContext(request))
The storing happens here: http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/files.py#L90. Django uses it's own API for accessing the file storage: http://docs.djangoproject.com/en/dev/ref/files/storage/. But if chunking is what you need you can go with Bartek's proposal!
Related
I'm working on web application in which user upload a video and we perform speech recognition on it and then translate its text in another language.So, if the request is POST then we call that function which perform these functionalities and if request is GET it should not call that but in my case,on POST request, function execute first and then POST request is submitted.And it perform functionality on the last video in database.
It gives the same result even if I put function call at the end of POST request condition statement and if I put function call out of POST request condition the function call on every reload of page which is not required and I don't know other ways how to solve this problem.
"""Django==2.0.2 views.py"""
def generatingsubtitle(request):
latestvideo = Video.objects.last()
videofile = latestvideo.videofile
path = settings.MEDIA_ROOT + videofile.name
filename = os.path.splitext(videofile.name)[0]
srtpath=settings.STATIC_ROOT+filename
if request.method == 'POST':
#function call
main(path, srtpath)
form = forms.VideoForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('generatingsubtitle'),
)
else:
form = VideoForm()
return render(request, 'app/generate.html', {
'form': form,
'videofile': videofile,
'filename':filename,
},
)
I expect that ,POST request is submitted first and we take path of newly submitted file and pass it to the function call but the actual output is, first call the function after executing function POST request is submitted.
Any help will be highly appreciated.
You should be only be doing your processing when the form is valid and the model is saved. The way you have it, you're fetching the last model before the form is even saved, meaning you're acting on the previous model, not the current one.
Move your subtitle function inside the form.is_valid() check, then get the path to the saved file from the saved model and feed that to your processing function.
def generatingsubtitle(request):
if request.method == 'POST':
form = forms.VideoForm(request.POST or None, request.FILES or None)
if form.is_valid():
# first save the model
video_model = form.save()
# get the path of the saved file from the model
video_path = video_model.videofile.path
# this may not be necessary anymore?
[filename, ext] = os.path.splitext(video_model.videofile.name)
srtpath = settings.STATIC_ROOT + filename
# generate subtitles
main(video_path, srtpath)
return HttpResponseRedirect(reverse('generatingsubtitle'))
You should not querying the database unless the method is 'POST'. Try this.
def generatingsubtitle(request):
filename = os.path.splitext(videofile.name)[0]
videofile = latestvideo.videofile
if request.method == 'POST':
form = forms.VideoForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
latestvideo = Video.objects.last()
path = settings.MEDIA_ROOT + videofile.name
srtpath=settings.STATIC_ROOT+filename
#function call
main(path, srtpath)
return HttpResponseRedirect(reverse('generatingsubtitle'))
else:
form = VideoForm() #edit
context = {
'form': form,
'videofile': videofile,
'filename':filename,
}
return render(request, 'app/generate.html', context)
I'm trying to save a file to disk, not in a class or anything just straight to disk but I can't for the life of me figure out how.
So far I've got:
View: `
def uploadview(request):
uploadtestvar='Uploadpage!'
request.session['test']='Is this working?'
if request.method == 'POST':
form=UploadForm(request.POST, request.FILES)
if form.is_valid():
forcetitle='test'
try:
pass
except:
pass
return HttpResponseRedirect('/test/')
else:
form=UploadForm()
return render(request, 'test/uploads.html',{'uploadtestvar':uploadtestvar, 'form':form})`
Form stolen directly from Django:
from django import forms
class UploadForm(forms.Form):
title=forms.CharField(max_length=50)
file=forms.FileField()
I've searched countless threads and found none that gives an example simple enough for me to understand how to get that request.FILES['file'] saved to disk somewhere. The possible filetypes are png, jpg, and pdf.
Pass FileSystemStorage to FileField in models where FileSystemStorage has the storage directory
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location = 'media/files/')
class UploadModel(models.Model):
title=forms.CharField(max_length = 50)
file=forms.FileField(storage = fs)
I have wrote a Django app for the user to upload files and see a list of uploaded files. I want to restrict the uploads to only using gif format and wrote a simple validator. Then I pass that validator in the Model, however it never triggers and the file is saved regardless of the format. Here's what I got so far.
views.py
def list(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
messages.add_message(request, messages.INFO, "Saved")
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('list'))
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render(
request,
'list.html',
{'documents': documents, 'form': form}
)
checkformat.py
def validate_file_type(upload):
if not (upload.name[-4:] == '.gif'):
raise ValidationError('File type not supported.')
models.py
from .checkformat import validate_file_type
def content_file_name(instance, filename):
return '/'.join(['documents', str(filename), filename])
class Document(models.Model):
docfile = models.FileField(upload_to=content_file_name, validators=[validate_file_type], null=False, verbose_name="File")
forms.py
class DocumentForm(forms.Form):
docfile = forms.FileField(
label='Select a file', widget=forms.FileInput(attrs={'accept':'image/gif'})
)
Is there something I'm missing? I've just started learning Django. Also, I know this is not a sercure way to check for a file type, but I just want to see it work to continue. Thank you for your time.
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
if not '.gif' in newdoc.name:
raise ValidationError('File type not supported.')
else:
newdoc.save()
messages.add_message(request, messages.INFO, "Saved")
try this simple solution, hope it works as you need
Looks right so far. Maybe it's simply a lower/upper case issue?
A more accurate solution might be:
import os
def validate_file_type(upload):
if os.path.splitext(upload.name)[1].lower() != '.gif':
raise ValidationError('File type not supported.')
If it's still not working try to add a break point within the validation method and check the value of upload.name.
I think the problem is the form is derived from a simple Model class, but in your case you must use ModelForm instead.
This way the form knows about the Document model, and you can do some fancy operations, like calling the save mehond in the Form object so save the model instance. Also the is_valid method calls all the validations defined in the model, in addition to the validations defined in the Form itself.
I have a fully functional Django web form that will upload and store images on Amazon S3.
How can I also create an additional re-sized copies of the same image that is being uploaded and upload them at the same time to Amazon S3?
Ideally, I will have two additional sizes (120x90, 240x180) saved to /small/ and /medium/ folders on S3.
For the upload to S3, I'm using django-storages and boto.
I have looked around and tried different ways, but it seems that all the thumb generating codes floating around are dealing with locally stored files or images that are already stored somewhere online.
My Code:
models.py
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
name = uuid.uuid4().hex
filename = "%s_%s.%s" % (instance.business_id, name, ext)
path = 'originals'
return os.path.join(path, filename)
class Photo(models.Model):
filename = models.ImageField(upload_to=content_file_name)
phototitle = models.CharField(max_length=50, null=True)
class Meta:
db_table = 'photo'
views.py
def create(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return ...
else:
form = UploadForm()
return render(request, 'upload.html', {
'form': form,
})
form.py
class UplaodForm(ModelForm):
class Meta:
model = Photo
fields = "__all__"
settings.py
AWS_STORAGE_BUCKET_NAME = '...'
AWS_ACCESS_KEY_ID = '...'
AWS_SECRET_ACCESS_KEY = '...'
...
INSTALLED_APPS = (
...
'storages',
My solution works with any storage, but I tested it for AWS via django-storage and boto3. I created a Storage named ThumbnailStorage inheriting from the default one (whatever it is) and added the creation of the thumbnails in method _save, so that I have the name and the content. As a last step I declared this ThumbnailStorage as the default Storage for the field:
the storage
import os
import io
from django.core.files.storage import get_storage_class
from PIL import Image
default_storage = get_storage_class()
class ThumbnailStorage(default_storage):
def _save(self, name, content):
if hasattr(content, 'content_type'):
if content.content_type.startswith('image/'):
self.generate_thumbnails(name, content)
return super()._save(name, content)
def generate_thumbnails(self, name, content):
name1, ext1 = os.path.splitext(name)
fname, ext = os.path.splitext(content.name)
format = (ext1 if ext1 != '.jpg' else '.jpeg').strip('.')
im = Image.open(content)
w, h = im.size
im.thumbnail((120, 90)) # <<< choose your dims
dest_filename = f'/small/{name}' # set your name
fh = default_storage().open(dest_filename, 'wb')
sfile = io.BytesIO()
im.save(sfile, format=format)
fh.write(sfile.getvalue())
fh.close()
the model
class Photo(models.Model):
filename = models.ImageField(
upload_to=content_file_name,
storage=TumbnailStorage() # <<< this is where the work is done
)
...
Note that jpg is not accepted by Pillow, so you need to translate to jpeg and that I was not able to im.save(fh) when the format is jpeg (while it works on png) so I had to add io.StringIO trick
I am working on a feature for a Django application that uploads files (images in my context) to the server. Everything is working fine but I am wondering how I can receive as callback the uploaded file path.
Here is my View:
def post(self, request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['uploadedFile'])
return redirect('/')
else:
form = UploadFileForm()
return render_to_response('index.html', {'form': form})
My Form:
class UploadFileForm(forms.Form):
uploadedFile = forms.FileField()
And my handler:
def handle_uploaded_file(source):
fd, filepath = tempfile.mkstemp(prefix=source.name, dir=FILE_UPLOAD_DIR)
with open(filepath, 'wb') as dest:
shutil.copyfileobj(source, dest)
return filepath
I know that handle_uploaded_file(request.FILES['uploadedFile']) from my view is the required string that I need as callback but how to receive it in the response?
It is possible to receive instead of my index.html (it is there just for testing purposes) the path of the image for further manipulation in the frontend part.
I might sound like a noob but I really want if that works somehow.
Also is there a way for my View to handle multiple file upload? It is something that I need to change in my handler?
Sorry for putting so many questions...
Try this:
file_path = handle_uploaded_file(request.FILES['uploadedFile'])
return render_to_response('index.html', {'form': form, 'file_path': file_path})