DRF file.read() contains HTML header info and not just file content - django

I'm not sure where the problem is, but file.read() should only give me file content. I'm printing out the first 200 chars and get content headers instead of just the uploaded file data.
Uploader
local_file = os.path.join(basedir, 'a.jpg')
url = baseurl + 'a.jpg'
files = {'file': open(local_file, 'rb')}
headers = {'Authorization': 'Token sometoken'}
r = requests.put(url, files=files, headers=headers)
print(r.status_code)
View
class FileUploadView(BaseAPIView):
parser_classes = (FileUploadParser,)
def put(self, request, filename):
file_obj = request.FILES['file']
data = file_obj.read()
print(data[:200])
return Response(status=HTTP_204_NO_CONTENT)
And the output printed is:
b'--139822073d614ac7935850dc6d9d06cd\r\nContent-Disposition: form-data; name="file"; filename="a.jpg"\r\n\r\n\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe1!(Exif\x00\x00II*\x00\x08\x00\x00\x00\r\x00\x0b\x00\x02\x00\r\x00\x00\x00\xaa\x00\x00\x00\x00\x01\t\x00\x01\x00\x00\x00x\x03\x00\x00\x01\x01\t\x00\x01\x00\x00\x00\xe8\x03\x00\x00\x0f\x01\x02\x00\x04\x00\x00\x00HTC\x00\x10\x01\x02\x00\x0b\x00\x00\x00\xb8\x00\x00'
How come I see all this extra data and not just the file content? Dis has been driving me bonkers and is probably going to be something simple.

With FileUploadParser you need to send the file content with data
with open(local_file, 'rb') as fh:
r = requests.put(url, data=fh, headers=headers, verify=False)

Related

xlxs file response not correct. It returning garbage symbols on response

def daily_report_summery(request):
body = request.body
data = json.loads(body)
date = data['date']
generate_summary_report_xl(date)
with open('./Daily_Report.xlsx', "rb") as file:
response = HttpResponse(file.read(),content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=Daily_Report.xlsx'
return response
I am getting this responce:
response
I want to send Daily_Report.xlsx file from backend.

Django Rest Framework function view post not working

So I am trying to serve a static file through a simple Django Rest framework function view. It gives me 200 code but doesn't download the file.
Here is the code :
#api_view(['POST'])
def download_file(request):
if request.method == 'POST':
serializer = MySerializer(data=request.data)
filename = 'file.xlsx'
file_full_path = "src/{0}".format(filename)
with open(file_full_path, 'rb') as f:
file = f.read()
response = HttpResponse(file, content_type="application/xls")
response['Content-Disposition'] = "attachment; filename={0}".format(filename)
response['Content-Length'] = os.path.getsize(file_full_path)
return response
return Response(status=status.HTTP_400_BAD_REQUEST)
What am I doing wrong here?
You are trying to download file with a HTTP POST method, I don't think it's a nice way. So try HTTP GET for downloading. If you wish to provide extra arguments (payload in POST method), you could do it using Query Parameter as /api/end/point/?param=value1&param2=value2.
So, try the following snippet,
#api_view(['GET'])
def download_file(request):
if request.method == 'GET':
filename = 'file.xlsx'
file_full_path = "src/{0}".format(filename)
with open(file_full_path, 'rb') as f:
file = f.read()
response = HttpResponse(file, content_type="application/xls")
response['Content-Disposition'] = "attachment; filename={0}".format(filename)
response['Content-Length'] = os.path.getsize(file_full_path)
return response
return Response(status=status.HTTP_400_BAD_REQUEST)

Django : How to upload csv file in unit test case using APIClient

I would like to write a unit test for a view on a Django REST Framework application. The test should upload a CSV file using the POST.
#staticmethod
def _file_upload(client, string, args, file_name):
base_path = os.path.dirname(os.path.realpath(__file__))
with open(base_path + file_name, 'rb') as data:
data = {
'file': data
}
response = client.post(reverse(string, args=[args]), data, format = "multipart")
return response.status_code, response.data
The above code I used which obviously doesn't work it shows the following error
Missing filename. Request should include a Content-Disposition header with a filename parameter.
The following code is the one that I want to test via unit testing.
class ChartOfAccounts(views.APIView):
parser_classes = (JSONParser, FileUploadParser)
def post(self, request, pk, *args, **kwargs):
request.FILES['file'].seek(0)
csv_data = CSVUtils.format_request_csv(request.FILES['file'])
try:
coa_data = CSVUtils.process_chart_of_accounts_csv(company, csv_data)
serializer = CoASerializer(coa_data, many=True)
if len(serializer.data) > 0:
return Utils.dispatch_success(request, serializer.data)
except Exception as e:
error = ["%s" % e]
return Utils.dispatch_failure(request, 'DATA_PARSING_ISSUE', error)
Any help regarding this is welcome. Thanks in advance
I have fixed my issue using the different approach with HTTP headers HTTP_CONTENT_DISPOSITION, HTTP_CONTENT_TYPE by this reference
And here is my code
#staticmethod
def _file_upload_csv( string, args, file_name):
base_path = os.path.dirname(os.path.realpath(__file__))
data = open(base_path + file_name, 'rb')
data = SimpleUploadedFile(content = data.read(),name = data.name,content_type='multipart/form-data')
factory = RequestFactory()
user = User.objects.get(username=UserConstant.ADMIN_USERNAME)
view = ChartOfAccounts.as_view()
content_type = 'multipart/form-data'
headers= {
'HTTP_CONTENT_TYPE': content_type,
'HTTP_CONTENT_DISPOSITION': 'attachment; filename='+file_name}
request = factory.post(reverse(string, args=[args]),{'file': data},
**headers)
force_authenticate(request, user=user)
response = view(request, args)
return response.status_code, response.data
**headers done the trick...
Here's what i did
#patch("pandas.read_csv")
#patch("pandas.DataFrame.to_sql")
def test_upload_csv_success(self, mock_read_csv, mock_to_sql) -> None:
"""Test uploading a csv file"""
file_name = "test.csv"
# Open file in write mode (Arrange)
with open(file_name, "w") as file:
writer = csv.writer(file)
# Add some rows in csv file
writer.writerow(["name", "area", "country_code2", "country_code3"])
writer.writerow(
["Albania", 28748, "AL", "ALB"],
)
writer.writerow(
["Algeria", 2381741, "DZ", "DZA"],
)
writer.writerow(
["Andorra", 468, "AD", "AND"],
)
# open file in read mode
data = open(file_name, "rb")
# Create a simple uploaded file
data = SimpleUploadedFile(
content=data.read(), name=data.name, content_type="multipart/form-data"
)
# Perform put request (Act)
res = self.client.put(CSV_URL, {"file_name": data}, format="multipart")
# Mock read_csv() and to_sql() functions provided by pandas module
mock_read_csv.return_value = True
mock_to_sql.return_value = True
# Assert
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
self.assertEqual(res.data, "Data set uploaded")
# Delete the test csv file
os.remove(file_name)

How do I receive XML file via POST in django

I'm trying to send XML file to django view using requests. I think the file is being sent by doing:
headers = {'Content-Type': 'application/xml'}
response = requests.post('http://localhost:8000/file/', data=file, headers=headers)
in view I have:
class ReceiveFile(TemplateView):
#method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
print request.read()
return HttpResponse('')
So how do I read file here in view and save it as xml again? request.read() gives me path from where file was sent.
Best, Blake
You are sending the file path, rather than the contents of the file.
You will need to send the contents of the file instead.
Assuming that your file contains valid XML:
headers = {'Content-Type': 'application/xml'}
open_file = open(file,'r')
file_contents = open_file.read()
response = requests.post('http://localhost:8000/file/', data=file_contents, headers=headers)

django download file from server to user's machine,or read online

I am uploading some .doc and .txt documents on my server, and i'd like to have two options:
-the user to be able to download the document
-the user to be able to read it online
i've read some code for the download function, but it doesn't seem to work.
my code:
def download_course(request, id):
course = Courses.objects.get(pk = id)
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(/root/)
return response
def save_course(request, classname):
classroom = Classroom.objects.get(classname = classname)
if request.method == 'POST':
form = CoursesForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['course'])
new_obj = form.save(commit=False)
new_obj.creator = request.user
new_obj.classroom = classroom
new_obj.save()
return HttpResponseRedirect('.')
else:
form = CoursesForm()
return render_to_response('courses/new_course.html', {
'form': form,
},
context_instance=RequestContext(request))
def handle_uploaded_file(f):
destination = open('root', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
any clue?
thanks!
You can open a File object to read the actual file, and then start download the file like this code:
path_to_file = os.path.realpath("random.xls")
f = open(path_to_file, 'r')
myfile = File(f)
response = HttpResponse(myfile, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=' + name
return response
path_to_file: is where the file is located on the server.
f = open(path_to_file, 'r') .. to read the file
the rest is to download the file.
Should the response['X-Sendfile'] be pointing to the file? It looks like it's only pointing at '/root/', which I'm guessing is just a directory. Maybe it should look more like this:
def download_course(request, id):
course = Courses.objects.get(pk = id)
path_to_file = get_path_to_course_download(course)
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
return response
Where get_path_to_course_download returns the location of the download in the file system (ex: /path/to/where/handle_uploaded_files/saves/files/the_file.doc)