File upload not working after changing models format - python

I have a model class similar to following -
class Document(models.Model):
docfile = models.FileField(upload_to='documents/%Y/%M/%D')
Everything is working fine and files are uploaded successfully based on directory structure.
Now I don't want to upload files in this format but simply all files in one folder so I changed the logic ..
class Document(models.Model):
docfile = models.FileField(upload_to='documents')
Now It is not uploading the files and throwing error. Maybe I need to run some command but I do not know what ??
Please suggest something
Edit1:
Ok .. I found that the actual problem lies somewhere else.
I have a view like this - (please ignore the bad spacing but that is fine in actual code)
def lists(request):
// Problematic Code Start
path = settings.MEDIA_URL + 'upload/location.txt'
f = open(path, 'w')
myfile = File(f)
myfile.write('Hello World')
myfile.closed
f.closed
// Problematic Code ends
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
filename = Document(docfile = request.FILES['docfile'])
filename.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('sdm:lists'))
#return render_to_response(reverse('sdm:lists'))
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_to_response(
'sdm/lists.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
When I remove the problematic code , everything works fine. (ignore the purpose of this weird code, actual interest is something bigger)
MEDIA_URL=/media/
Here is the error:
IOError at /sdm/lists
[Errno 2] No such file or directory: '/media/upload/location.txt'
Although File Exists and all permissions are www-data:www-data with 755

"problematic" code indeed - whoever wrote this should find another job. This code is wrong in more than one way (using MEDIA_URL instead of MEDIA_ROOT - which is the cause of the IOError you get - and also badly misusing Python's dead simple file objects) and totally useless, and looks like a leftover of someone programming by accident. To make a long story short : just remove it and you'll be fine.

Related

How to access uploaded images via URL in Django?

I'm building a simple blog style web app for a friend. I am using CK editor and mostly stock Django 4.1. I'm stumped in how in what would be the best approach to let the creator to upload and serve images in their posts. CK editor allows you to add images via URL and I'd like for it to be possible to the creator to upload their files to the backend and would like to know if there are best practices when it comes to this.
Right now I have this:
def editor_upload(request):
if request.method == 'GET':
form = UploadFileForm
path = os.path.join(settings.STATIC_ROOT, 'files')
files = os.listdir(path)
return render(request, 'upload.html', {"form": form, "files": files})
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
file = request.FILES['file']
title = str(file)
if form.is_valid():
path = os.path.join(settings.STATIC_ROOT, 'files')
fs = FileSystemStorage(location=path)
fs.save(title, file)
return redirect('/editor/upload')
def open_file(request, file_name):
print(file_name)
return render(request, 'file.html', {"file": file_name})
in editor_upload, the user can see what files there are in the specified folder (but cannot access them yet) and there is the logic to upload new pictures to the folder. The problem comes now: I don't know how to properly access them.
In open_file, the request receives the name of the file and gives it to the HTML templating. This does not work because the template looks into the project folder and not into the root static folder. I must admit I'm a bit lost with how the static folders in Django works because I've been mostly utilizing just the project static folder. Also, I don't think this would work for CK editor to grab the image.
Any ideas on how I could solve this? I also tried doing it by uploading the image to a database but I had kind of the same problem. I need to somehow generate an URL to pass into CK editor. Many thanks!

Save uploaded files in subfolder depending on request

I have a website, that lets user upload files. These files are attached to a node, which ID is part of the upload request. Since the same file might be attached to different nodes, Django will rename the file by adding a hash to the filename. Thus if a user downloads a previously uploaded file, it won't have the original filename.
Is it possible to create a subdirectory (named after the node ID) inside the media folder a file is uploaded? The closest solution I found was to change the System Storage of the FileField, but this is static for all files of that one model. Or is there another, better way to solve the problem with duplicate files?
Model:
class Attachment(models.Model):
node = models.IntegerField(default=-1)
file = models.FileField(upload_to=".")
View:
def file_upload(request):
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = Attachment(file=request.FILES["file"], node_id=request.POST["node_id"])
instance.save()
return HttpResponse(instance.file.url)
Yes, take a look at the documentation on upload_to.
You could do something like this, which includes the node id (defined as an integer in your model in the upload_to path:
def attachment_path_with_node(instance, filename):
return "attachments/{}/{}".format(instance.node, filename)
class Attachment(models.Model):
node = models.IntegerField(default=-1)
file = models.FileField(upload_to=attachment_path_with_node)
Also path can be further customized like this:
document = models.FileField(upload_to='documents/%Y/%m/%d/')
which would upload to: MEDIA_ROOT/documents/2020/12/22/.
See more at https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html

Django - Uploaded file type validation

I need to validate the file type of the uploaded file and should allow only pdf, plain test and MS word files. Here is my model and and the form with validation function. But, I'm able to upload files even without the extension.
class Section(models.Model):
content = models.FileField(upload_to="documents")
class SectionForm(forms.ModelForm):
class Meta:
model = Section
FILE_EXT_WHITELIST = ['pdf','text','msword']
def clean_content(self):
content = self.cleaned_data['content']
if content:
file_type = content.content_type.split('/')[0]
print file_type
if len(content.name.split('.')) == 1:
raise forms.ValidationError("File type is not supported.")
if content.name.split('.')[-1] in self.FILE_EXT_WHITELIST:
return content
else:
raise forms.ValidationError("Only '.txt' and '.pdf' files are allowed.")
Here is the view,
def section_update(request, object_id):
section = models.Section.objects.get(pk=object_id)
if 'content' in request.FILES:
if request.FILES['content'].name.split('.')[-1] == "pdf":
content_file = ContentFile(request.FILES['content'].read())
content_type = "pdf"
section.content.save("test"+'.'+content_type , content_file)
section.save()
In my view, I'm just saving the file from the request.FILE. I thought while save() it'll call the clean_content and do content-type validation. I guess, the clean_content is not at all calling for validation.
You approach will not work: As an attacker, I could simply forge the HTML header to send you anything with the mime type text/plain.
The correct solution is to use a tool like file(1) on Unix to examine the content of the file to determine what it is. Note that there is no good way to know whether something is really plain text. If the file is saved in 16 bit Unicode, the "plain text" can even contain 0 bytes.
See this question for options how to do this: How to find the mime type of a file in python?
You can use python-magic
import magic
magic.from_file('/my/file.jpg', mime=True)
# image/jpeg
This is an old question, but for later users main question as mentioned in comments is why field validation not happens, and as described in django documentation field validation execute when you call is_valid(). So must use something sa bellow in view to activate field validation:
section = models.Section.objects.get(pk=object_id)
if request.method == 'POST':
form = SectionForm(request.POST, request.FILES)
if form.is_valid:
do_something_with_form
Form validation happens when the data is cleaned. If you want to customize this process, there are various places to make changes, each one serving a different purpose. Three types of cleaning methods are run during form processing. These are normally executed when you call the is_valid() method on a form

How to unzip a zip file in django , which contains .shp , .prj , .shx and .dbf , thus being able to upload in the database?

I have uploaded a zip file using django in a local directory . How do I unzip it , and store it in 3 different files ?
Ok . Let me explain my problem a bit more in detail .
def upload(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.handle(request.FILES['file_obj'])
#form.save() # if a modelform
#form.cleaned_data['user'] = request.user
z = zipfile.ZipFile('file_obj')
for files in z.namelist():
file(files,'wb').write(z.read(files))
z.close()
return render_to_response('uploaded.html', RequestContext(request,{}))
else:
form = UploadForm()
return render_to_response('upload.html', RequestContext(request,{'form': form})
)
This is my upload form , which is supposed to work . file_obj contains the uploaded zip file . But it doesnt give any output .
It doesnt look like you're actually opening the upload, but a file in the current directory called 'file_obj'. You want something more like
z = zipfile.ZipFile(request.FILES['file_obj'])
also I might be wrong, but i don't think you need the form.handle() call at all, at least I've never used it, but i might stand corrected.
Also, you want to be very careful here, as you're writing out to the filenames contained in the zipfile, which for all you know could be absolute paths somewhere. You need to be very careful with that. In case I didn't say it, be careful with user created content, it might be malicious.

import csv file into mysql database using django web application

i try to upload a csv file into my web application and store it into mysql database but failed.Please can anyone help me?
my user.py script:
def import_contact(request):
if request.method == 'POST':
form = UploadContactForm(request.POST, request.FILES)
if form.is_valid():
csvfile = request.FILES['file']
print csvfile
csvfile.read()
testReader = csv.reader(csvfile,delimiter=' ', quotechar='|')
for row in testReader:
print "|".join(row)
return HttpResponseRedirect('/admin')
else:
form = UploadContactForm()
vars = RequestContext(request, { 'form': form })
return render_to_response('admin/import_contact.html', vars)
my forms.py script:
class UploadContactForm(forms.Form):
file = forms.FileField(label='File:', error_messages = {'required': 'File required'})
Since you haven't provided the code for the getcsv function, I'll have to use my crystal ball here a bit.
One reason why the print in the for row in testReader: loop isn't working is that getcsv may already processes the file. Use the seek method to reset the objects position in the file to zero again. That way the for loop will process it properly.
Another reason why there's nothing stored in the database might be that in the code you've supplied there doesn't seem to be a reference to a model. So how should Django know what it should store and where?

Categories