Django save uploaded file - python

I want to upload a file, what I am able to do with the code stated below, but I also need to save all the uploads in different folder with different names. If 2 users upload the same file from browser, then in the folder it should be saved with different name or Unique Identification number.
Following is my code:
views.py
from django.shortcuts import render
import openpyxl
def index(request):
if "GET" == request.method:
return render(request, 'myapp/index.html', {})
else:
excel_file = request.FILES["excel_file"]
# you may put validations here to check extension or file size
wb = openpyxl.load_workbook(excel_file)
# getting all sheets
sheets = wb.sheetnames
print(sheets)
# getting a particular sheet
worksheet = wb["Sheet1"]
print(worksheet)
# getting active sheet
active_sheet = wb.active
print(active_sheet)
# reading a cell
print(worksheet["A1"].value)
excel_data = list()
# iterating over the rows and
# getting value from each cell in row
for row in worksheet.iter_rows():
row_data = list()
for cell in row:
row_data.append(str(cell.value))
print(cell.value)
excel_data.append(row_data)
return render(request, 'myapp/index.html', {"excel_data":excel_data})

Give you a Django FileField way Implemention:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
suffix = filename[filename.rindex(".")+1:]
return 'upfiles/{0}/{1}.{2}'.format(instance.user.username, get_randomfilename(),suffix)
class Picture(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
file = models.ImageField(upload_to=user_directory_path)
date_added = models.DateTimeField(auto_now_add=True)
#parser_classes((MultiPartParser,))
#permission_classes((IsAuthenticated, ))
def upload_picture(request):
'''
:input :{"file":f}
:return:{"id":pictureId}
'''
if "file" in request.FILES:
f = request.FILES["file"]
picture = Picture()
picture.user= request.user
picture.file = f
picture.save()
return Response(data={"id":picture.id})
else:
return Response({},status=status.HTTP_400_BAD_REQUEST)

Related

File handling in django

I am trying to access the csv file which i passed in my form and saved in media directory.
I am able to access the file if i manually enter the path(localhost://8000/media/1.csv)
but it throws an error saying "No such file or directory" when accessing from open function.
def home(request):
print("Rendering Home...")
if request.method == "POST":
uploaded_file = request.FILES['csvFile']
fs = FileSystemStorage()
name = fs.save(uploaded_file.name,uploaded_file)
url = fs.url(name)
csv_fp = open(f'{url}', 'r') //ERROR:"No such file or dir media/1.csv"
reader = csv.DictReader(csv_fp)
headers = [col for col in reader.fieldnames]
out = [row for row in reader]
return render(request, 'home.html', {'data' : out, 'headers' : headers})
return render(request,"home.html")
have you tried .path instead of .name
file = open(filename.path' 'rb').read()
The problem was the path being given to open function
csv_fp = default_storage.open(os.path.join(settings.MEDIA_ROOT, name), 'r')
simply did the trick :)

Export CSV files in a bulk in Django

I'm creating a custom administration action to download a list of orders as a CSV file.
I've this in my orders/admin.py:
def export_to_csv(modeladmin, request, queryset):
opts = modeladmin.model._meta # opts = options
for order in queryset:
content_disposition = f'attachment; filename=OrderID-{order.id}.csv'
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = content_disposition
writer = csv.writer(response)
fields = [field for field in opts.get_fields() if not field.many_to_many
and not field.one_to_many]
writer.writerow([field.verbose_name for field in fields])
# Write data rows
for obj in queryset:
data_row = []
for field in fields:
value = getattr(obj, field.name)
if isinstance(value, datetime.datetime):
value = value.strftime('%d/%m/%Y')
data_row.append(value)
writer.writerow(data_row)
return response
However, this code doesn't download more than one csv file Even when I've selected more than one.
You cannot download several files via 1 HTTP request, details.
So, you can zip your csvs in one zip file and return it like this answer describes.

How to use Post-save Signal when uploading document, and saving before and after altering document?

I want save document when uploaded and run pandas script and save that script but also to forward to user do download it. How to do it simple way?
This is how I tried to do it, upload and save upload works, but pandas script is not working.
def my_view(request):
message = 'Upload as many files as you want!'
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
#This part is doing calculations for uploaded file
dfs = pd.read_excel(newdoc, sheet_name=None)
with pd.ExcelWriter('output_' + newdoc + 'xlsx') as writer:
for name, df in dfs.items():
print(name)
data = df.eval('d = column1 / column2')
ooutput = data.eval('e = column1 / d')
ooutput.to_excel(writer, sheet_name=name)
output = io.BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
newdoc.to_excel(writer, index=False)
writer.save()
output.seek(0)
response = HttpResponse(output,
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s.xlsx' % 'Download'
return response
return redirect('results')
else:
message = 'The form is not valid. Fix the following error:'
else:
form = DocumentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form, 'message': message}
return render(request, 'list.html', context)
def results(request):
documents = Document.objects.all()
context = {'documents': documents}
return render(request, 'results.html', context)
dfs = pd.read_excel(newdoc, sheet_name=None)
You are passing newdoc here, which is your model, not a IO object.
Try
dfs = pd.read_excel(newdoc.docfile, sheet_name=None)
or
dfs = pd.read_excel(newdoc.docfile.file, sheet_name=None)
This is the not answer but my suggestion, you are following the wrong way of implementation.
You can set background process in Celery
After the job is done in Celery you can mail/notify the User with download URL.
The above given solution will be long but scalable and performance-oriented as well.

Merge Single Excel Worksheet to one Workbook Using Python

I have a django site that will take uploaded .xls files and merge them into one Workbook
I am having trouble merging the uploaded the Worksdheets. Here is a sample of my code:
import pyexcel
import openpyxl
from pyexcel.cookbook import merge_all_to_a_book
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
type_of_case = form.cleaned_data['Selection_type']
case = form.cleaned_data['Case']
new_name = type_of_case + '-' +case + '.xlsx'
file_names = []
objects=[]
for x in request.FILES.getlist('Files'):
filename = x.name
file_names.append(filename)
excel_ojects = x.read
objects.append(excel_ojects)
file_names.append(filename)
print (x.content_type)
merge_all_to_a_book(objects, outfilename=(new_name))
I've tried changing the merge_all_to_a_book to option (objects) and (file_names) but they both produce an error saying:
OSError: Unsupported file type
However when I print the content type I get:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Can anyone help me to merge these freaking spreadsheets?

Django-importing excel file into django models

I need user to upload an excel file via the form provided and i need to process that uploaded excel file to save the data in my model.
models.py
class Patient_Record(models.Model):
Patient_id=models.IntegerField(unique=True)
Patient_sex=models.CharField(max_length=1,choices=Gender)
Patient_name=models.CharField(max_length=20)
Patient_sugar=models.DecimalField(decimal_places=3,max_digits=6)
Patient_chlorestrol=models.DecimalField(decimal_places=3,max_digits=6)
Patient_iron=models.DecimalField(decimal_places=3,max_digits=6)
Patient_haemoglobin=models.DecimalField(decimal_places=3,max_digits=6)
def __str__(self):
return self.pat_name
I have simple form to upload the file.
<form method="POST" class="post-form" action="../Uploaded_file" enctype="multipart/form-data" name="myfile">{% csrf_token %}
{{ upload_form.as_p }}
<input type="submit" value="Upload" name="Upload" class="btn btn-primary">
</form>
Can someone help me with the code to parse a excel file using POST to this model.
I tried using many different methods but couldn't succeed in it.
You require xlrd library to extract the data from excel sheet.
Check out following link https://pypi.python.org/pypi/xlrd
This is the example snippet. You may modify it according to your code.
In Forms.py create a model form with following field.
class UpdateDetailsForm(forms.Form):
excel_file = forms.FileField(label='Excel File',required=False,validators=[validate_file_extension])
Then in corresponding views.py
def update_details(request):
message=''
if request.method == 'POST':
form = UpdateDetailsForm(request.POST,request.FILES)
if form.is_valid():
#import your django model here like from django.appname.models import model_name
excel_file = request.FILES['excel_file']
i=0
try:
import os
import tempfile
import xlrd
fd, tmp = tempfile.mkstemp()
with os.fdopen(fd, 'w') as out:
out.write(excel_file.read())
book=xlrd.open_workbook(fd)
sh = book.sheet_by_index(0)
for rx in range(1,sh.nrows):
obj=Patient_Record(Patient_id=str(sh.row(rx)[0].value),Patient_sex=str(sh.row(rx)[1].value)) # similiary populate according to your model
obj.save()
i=i+1;
finally:
os.unlink(tmp)
else:
message='Invalid Entries'
else:
form = UpdateDetailsForm()
return render_to_response('admin/import_data.html', {'form':form,'message':message},context_instance=RequestContext(request))
In Python 3.6 and Django 2.0 the following rises the error
Exception Type: PermissionError
Exception Value:[WinError 32]
def upload_file(request):
message=''
if request.method == 'POST':
form = FormUploadFileData(request.POST, request.FILES)
if form.is_valid():
from projects.models import Project
excel_file = request.FILES['excel_file']
try:
import os
import tempfile
import xlrd
fd, tmp = tempfile.mkstemp() # create two temporary file
with os.open(fd, 'wb') as out: # create new file objects
out.write(excel_file.read())
book = xlrd.open_workbook(fd)
sheet = book.sheet_by_index(0)
obj=Project(
project_title = sheet.cell_value(rowx=1, colx=1),
project_sector = sheet.cell_value(rowx=2, colx=1),
project_location = sheet.cell_value(rowx=3, colx=1),
project_tot_cost = sheet.cell_value(rowx=4, colx=1),
project_descr = sheet.cell_value(rowx=5, colx=1),
project_fund = sheet.cell_value(rowx=6, colx=1),
project_cofin = sheet.cell_value(rowx=7, colx=1),
project_applicant = sheet.cell_value(rowx=8, colx=1)
)
obj.save()
finally:
os.unlink(tmp)
else:
message='Invalid Entries'
else:
form = FormUploadFileData()
return render(request,'upload.html', {'form':form,'message':message})
There is an issue in the solution proposed:
book=xlrd.open_workbook(fd) should be book=xlrd.open_workbook(tmp) as open_workhook search for a file path
[Worked in Python 3.6, Django 2.0]
excel_file = request.FILES['excel_file']
import os
import tempfile
import xlrd
fd, path = tempfile.mkstemp() # mkstemp returns a tuple: an integer (index) called file descriptor used by OS to refer to a file and its path
try:
with os.fdopen(fd, 'wb') as tmp:
tmp.write(excel_file.read())
book = xlrd.open_workbook(path)
sheet = book.sheet_by_index(0)
obj=Project(
project_title = sheet.cell_value(rowx=1, colx=1),
project_sector = sheet.cell_value(rowx=2, colx=1),
project_location = sheet.cell_value(rowx=3, colx=1),
project_tot_cost = sheet.cell_value(rowx=4, colx=1),
project_descr = sheet.cell_value(rowx=5, colx=1),
project_fund = sheet.cell_value(rowx=6, colx=1),
project_cofin = sheet.cell_value(rowx=7, colx=1),
project_applicant = sheet.cell_value(rowx=8, colx=1)
)
obj.save()
finally:
os.remove(path)

Categories