How to upload file larger than 2.5MB to django? - django

I my goal is to upload file larger than 2.5MB to django server. I can upload file, if it is smaller than 2.5MB, if file is bigger then 2.5MB I get 413 Payload too large in browser. And I do not understand why.
I set MAX_UPLOAD_SIZE = 429916160 MEDIA_ROOT = os.path.join(BASE_DIR, 'files')
MEDIA_URL = '/files/' and FILE_UPLOAD_MAX_MEMORY_SIZE = MAX_UPLOAD_SIZE in my settings.py. Currently I use django development server without apache or nginx.
My models.py:
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.vsdx']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
class UpLoadFile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to=path, validators=[validate_file_extension])
uploaded_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username + '/' + self.file.name
class UploadFileForm(forms.ModelForm):
file = forms.FileField(required=True, label="")
class Meta:
model = UpLoadFile
fields = ('file',)
views.py:
if request.method == 'GET':
upload_file_form = UploadFileForm()
all_files = UpLoadFile.objects.select_related("user").filter(user__username=request.user).all().order_by("-uploaded_at")
return render(request, 'interface/files.html', {'page_title': 'Datoteke',
'files': all_files,
'upload_file_form': upload_file_form})
elif request.method == 'POST':
if "upload-file" in request.POST:
file_name = request.FILES.get("file")
username = request.user
if bool(os.path.exists(f'files/{username}/{file_name}')):
messages.error(request, "Datoteka s tem imenom že obstaja!")
return redirect('files')
else:
upload_file_form = UploadFileForm(request.POST, request.FILES)
upload_file_form.instance.user = username
if upload_file_form.is_valid():
upload_file_form.save()
messages.success(request, "Datoteka je uspešno dodana!")
return redirect('files')
messages.error(request, "Te vrste datoteke ni mogoče naložiti na server. Preverite če ima datoteka .vsdx končnico.")
return redirect('files')
Were and what should I set to be able to upload file larger than 2.5MB?
I would appreciate any advice on how to handle this kind of file.

Include this in your settings.py file
DATA_UPLOAD_MAX_MEMORY_SIZE = 50242880

Related

Upload in Django

I was trying to understand how to upload files using Django, so I used the example (latest version, upload is working):
https://github.com/axelpale/minimal-django-file-upload-example
I have a few Questions now:
How do I set a max file size? (I have checked the documentation of Django, but I don't get it)
Is there a way for me to read the file before the user uploads it?
(i.e a program that checks certain things and if they are ok, it can be uploaded)
Here is some code...
model.py:
class Document(models.Model):
name= models.CharField(max_length=500)
docfile= models.FileField(upload_to='documents/%Y/%m/%d', verbose_name="", validators=[validate_file_size])
def __str__(self):
return self.name + ": " + str(self.docfile)
validators.py:
def validate_file_size(value):
filesize= value.size
if filesize > 20971520:
raise ValidationError("File too big")
else:
return value
views.py:
def uploadView(request):
message = 'Upload your .csv-File'
if request.method == 'POST':
form = documentForm(request.POST, request.FILES)
if form.is_valid():
newDoc = Document(docfile=request.FILES['docfile'])
newDoc.save()
return redirect(uploadView)
else:
message = 'The form is not valid.'
else:
form = documentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form, 'message': message}
return render(request, 'upload.html', context)

Django: How can I changes values via views.py

I am trying to make a "upload" page so that I can upload a file and process to postgres DB using pd.to_sql(). All the data has been succefuly recorded into DB, but cannot change the values of "is_recorded" and "has_issue". Here is the files I am working on so far.
In upload/models.py
from django.db import models
class Upload(models.Model):
file_name = models.FileField(upload_to='uploads', max_length=255)
uploaded = models.DateTimeField(auto_now_add=True)
# When uploaded successfully
is_recorded = models.BooleanField(default=False)
# When it has a problem to fix
has_issue = models.BooleanField(default=False)
def __str__(self):
return f'{self.file_name}: {self.id}'
In views.py
import os
from django.shortcuts import render
from core.db_implements import upload_csv_to_DB
from upload.forms import UploadForm
from upload.models import Upload
def upload_view(request):
error_message = None
success_message = None
form = UploadForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
form = UploadForm()
try:
obj = Upload.objects.get(is_recorded=False)
recorded, issue, success_message, error_message = ***upload_csv_to_DB***(obj)
obj.is_recorded = recorded
obj.has_issue = issue
obj.save()
success_message = success_message
error_message = error_message
except:
error_message = 'Something went wrong.'
context={
'form': form,
'success_message': success_message,
'error_message': error_message,
}
return render(request, 'upload/upload.html', context)
In forms.py
from django import forms
from django.db.models import fields
from django.forms.fields import FileField
from django.forms.models import ModelFormMetaclass
from .models import Upload
class UploadForm(forms.ModelForm):
# file_name = forms.FileField(max_length=255, label=False)
class Meta:
model=Upload
fields = ('file_name',)
widgets = {
'file_name': forms.FileInput(
attrs={
'class': 'form-control',
}
)
}
I am outsource the function (upload_csv_to_DB) which takes file object and convert to dataframe and record into DB. If its success, recorded=True with sucess_message supposed to be returned, however, if somethings wrong, issue=True with error_message supposed to be returned. Anyways recorded and issue are always False, and having error_message from except clause 'Something went wrong.'. Please advise me...
I figured out the reason. I did not initialize the return value of outsourced function, upload_csv_to_DB. After initialize the returned values to be, everything works as intended. Here is the code which solves the problem.
In upload_csv_to_DB.py:
def upload_csv_to_DB(csv_obj):
recorded = False
issue = False
success_message = None
error_message = None
upload_file = csv_obj.file_name.path
...
return (recorded, issue, success_message, error_message)
In views.py:
def upload_view(request):
error_message = None
success_message = None
recorded =False
issue = False
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
try:
obj = Upload.objects.get(is_recorded=False)
recorded, issue, success_message, error_message = upload_csv_to_DB(obj)
obj.is_recorded = recorded
obj.has_issue = issue
obj.save()
success_message = success_message
error_message = error_message
except:
error_message = 'Something went wrong.'
else:
form = UploadForm()
context={
'form': form,
'success_message': success_message,
'error_message': error_message,
}
return render(request, 'upload/upload.html', context)

How to save image to user folder in django?

I'd like to save uploaded images to separate folders. So for example user 4 photos should be stored in /media/images/4/
Here is the function and model and views that I came up with:
Model:
def get_uplaod_file_name(user,filename):
return 'photos/%s/%s_%s' % str(user.id), (str(time()).replace('.','_'), filename)
class UserPic(models.Model):
user = models.ForeignKey(User, unique=False)
picfile = ImageWithThumbsField(upload_to= get_uplaod_file_name, sizes=((200,200),(1200,1200)))
caption = models.CharField(max_length=200 , blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
#models.permalink
def get_absolute_url(self):
return ('view_pirate', None, {'user': self.account.user})
def __unicode__(self):
return unicode(self.picfile.name)
Views:
#login_required
def upload(request):
# Handle file upload
thisuser =User.objects.get(username = request.user.username)
# Load pics of this user
if request.method == 'POST':
picform = PicForm(request.POST, request.FILES)
if picform.is_valid():
newpic = UserPic(picfile = request.FILES['picfile'])
newpic = picform.save(commit=False)
newpic.user_id = request.user.id
newpic.save()
message = "file %s is uploaded" % newpic
else:
picform = PicForm() # A empty, unbound form
args= {}
args['picform'] = picform
return render_to_response('userpics/upload.html',args,
context_instance=RequestContext(request))
However, after many tweaks of get_uplaod_file_name it still does not work. I get errors like:
TypeError at /pics/upload/
not enough arguments for format string
Appreciate your help to resolve this.
You should pass a tuple to the string formatting operator:
def get_uplaod_file_name(userpic, filename):
return u'photos/%s/%s_%s' % (str(userpic.user.id),
str(time()).replace('.', '_'),
filename)
Note the first and last round brackets.
Also note the unicode prefix u' which is mandatory in case if user will upload a file with non-ascii symbols in the name.

FIle upload with chunks: avoid saving it twice

I use a custom function to upload a file splitting it in chunks, as documented here.
My problem is that calling save() after handle_uploaded_file() uploads my file twice, one into "MEDIA_URL/my_path" dir and one into "MEDIA_URL".
But I would like to have only one upload, the one with chunks.
It is possible to force save() to make 'chunked' upload?
Or should I use different approaches?
Thank you.
models.py
class ShapeFile(models.Model):
name = models.CharField(max_length=100)
srid = models.ForeignKey(SpatialRefSys)
user = models.ForeignKey(User)
color_table = models.ForeignKey(ColorTable)
file = models.FileField(upload_to="my_path")
class Meta:
unique_together = ('name', 'user')
forms.py
class UploadForm(ModelForm):
class Meta:
model = ShapeFile
fields = ('name','user','srid','file','color_table')
widgets = {'srid': TextInput(),
'user': HiddenInput()
views.py
def handle_uploaded_file(fileName, filePath):
with open(filePath, 'wb+') as destination:
for chunk in fileName.chunks():
destination.write(chunk)
#login_required
def shapeIng(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
req = request.POST
# Split uploaded file into chunks
fileName = request.FILES['file']
filePath = ShapeFile(file=fileName).file.path
handle_uploaded_file(fileName, filePath)
form.save()
messages.success(request, 'Shapefile upload succesful!')
return redirect('shapeCreated')
else:
messages.error(request, 'Something went wrong uploading Shapefile.')
else: # request.method == 'GET'
form = UploadForm(initial={'user': request.user})
return render_to_response('my_app/base_shapeIngestion.html',
{'form': form},
context_instance=RequestContext(request))
change your view function to this:
def testupload2(request):
if request.method == 'POST':
file_name=request.FILES['file']
form = SomeForm(request.POST, request.FILES)
if form.is_valid():
dest_file = open('C:/prototype/upload/'+ str(file_name), 'wb+')
path = 'C:/prototype/upload/'+ str(file_name)
for chunk in request.FILES['file'].chunks():
dest_file.write(chunk)
dest_file.close()
t = get_template("testupload2.html")
lst = os.listdir('C:/downloads/prototype/prototype/upload/')
html = t.render(Context({'MEDIA_URL':'http://127.0.0.1:8000/site_media/'}))
return HttpResponse(html)

from django form uploading a image in windows development server

I have a model like this
class Ask(models.Model):
name = models.CharField(max_length=500)
designation = models.CharField(max_length=200, blank=True)
email = models.EmailField()
phone = models.CharField(max_length=20, blank=True)
avatar = models.ImageField(upload_to="ask/users/avaters", blank=True, )
question = models.CharField(max_length= 1024)
ques_time = models.DateField(auto_now_add=True)
answer = models.TextField(blank=True)
ans_time = models.DateField(blank=True,null=True, auto_now=True)
display = models.BooleanField()
asker_ip = models.CharField(max_length=100, blank=True)
def __unicode__(self):
return self.name
my forms.py is like this
class AskForm(forms.Form):
name = forms.CharField(required=True, max_length= 500)
email = forms.EmailField(required=True)
avater = forms.ImageField()
question = forms.CharField(required=True, max_length=1024)
my view is like this
def handle_uploaded_file(f):
destination = open('D:/dsite/ak47/media/ask/users/avaters', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
def submit_page(request):
data = {}
if request.method == 'POST':
data = request.POST.copy()
form = AskForm(request.POST, request.FILES)
if form.is_valid():
ask = Ask()
ask.name = form.cleaned_data['name']
ask.email = form.cleaned_data['email']
ask.question = form.cleaned_data['question']
handle_uploaded_file(request.FILES['avater'])
ask.save()
return HttpResponseRedirect('/ask/')
else:
form = AskForm()
return render_to_response('ask/index.html', {'form': form,})
problem is in my windows development server. When I hit submit it give me a io error. Permission denied. I tried give the folder a full control permission. I'm assuming the error is for other reason. Because I can upload from admin panel.
You're trying to save file into folder, but did not specified file name.
Your handle function should be:
def handle_uploaded_file(f):
save_path = 'D:/dsite/ak47/media/ask/users/avaters'
destination = open(os.path.join(save_path,f.name), 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
and dont forget add at top of your views.py
import os
Another solution for this case
Use ModelForm and it's features. You dont have to handle manually file uploading, it's already done by ModelForm. Your forms.py should look like this:
from .models import Ask
class AskForm(forms.ModelForm):
class Meta:
model = Ask
fields = ('name', 'email', 'question', 'avater')
Your views.py should look like this:
def submit_page(request):
if request.method == 'POST':
form = AskForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/ask/')
else:
form = AskForm()
return render_to_response('ask/index.html', {'form': form,})
ModelForm will automagically handle all submitted data and create/save new Ask object for it.