How do I receive XML file via POST in django - 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)

Related

Send csv file via email django

I want to attach a csv file to an email.
i wrote a get method like this :
def get(self, request, *args, **kwargs):
serializer = self.get_serializer(self.get_queryset(), many=True)
file_format = request.query_params.get("file_format", "csv")
if file_format == "csv":
data_file = export_to_csv(
serializer.data,
list(self.get_serializer().Meta.fields),
"students"),
)
return data_file
this API generate a link to download the csv... but when I PDB the data_file I find out it is <HttpResponse status_code=200, "text/csv">
this the export_to_csv function :
def export_to_csv(data, titles, file_name):
#This function will export the data in the form of csv file
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = "attachment; filename={}.csv".format(file_name)
writer = csv.DictWriter(
response,
fieldnames=titles,
extrasaction="ignore",
)
# create dict from translation of headers
headers = {title: _(title).replace("_", " ").title() for title in titles}
# write translated headers
writer.writerow(headers)
# write data to csv file
for row in data:
writer.writerow(row)
return response
The question is how can I attach the generated csv to the email
Refer to this, it's a neat documentation
https://docs.djangoproject.com/en/4.1/topics/email/#django.core.mail.EmailMessage
you can attach filenames with email, that way you can send attachments.

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)

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

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)

Django test client get row id from query

How can i print the id from the response in the below code.The user does exist in the DB.Also i come across this error.
from django.test import Client
c = Client(enforce_csrf_checks=False)
response = c.post('/reg/_user/', {'firstname': 'test', 'lastname' : '_test'})
views get_user
def _user(request):
try:
response_dict = {}
qd = request.POST
firstname = qd.__getitem__('firstname')
lastname = qd.__getitem__('lastname')
up = UserProfile.objects.get(first_name=firstname,last_name=lastname)
print up.id
return up.id
except:
pass
Error:
response = c.post('/reg/_user/', {'firstname': 'test', 'lastname' : '_test'})
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 483, in post
response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 302, in post
return self.request(**r)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 444, in request
six.reraise(*exc_info)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 201, in get_response
response = middleware_method(request, response)
File "/usr/local/lib/python2.7/dist-packages/django/middleware/clickjacking.py", line 30, in process_response
if response.get('X-Frame-Options', None) is not None:
AttributeError: 'UserProfile' object has no attribute 'get'
The problem is not with your tests, but with the view itself. In Django a view always has to return a HttpResponse object. Sometimes this is achieved using a shortcut function like render(), but it in turn also returns an HttpResponse object.
If for some reason you just want to return an otherwise empty page with this single value you could change
return up.id
to
return HttpResponse(up.id)
Also, I wonder: Did you create the view just to test UserProfile and don't use it as a view on the actual site? If so, this code doesn't belong in a view, it should be put into the unittest itself. You should only use the test client to test actual, real views.
On an mostly unrelated, but quite important note. This:
try:
# your view code
except:
pass
is a strong antipattern. Why would you want to silence all the potential problems? You should really stop doing that.

Django - Get uploaded file type / mimetype

Is there a way to get the content type of an upload file when overwriting the models save method? I have tried this:
def save(self):
print(self.file.content_type)
super(Media, self).save()
But it did not work. In this example, self.file is a model.FileField:
file = models.FileField(upload_to='uploads/%m-%Y/')
Edit: I want to be able to save the content type to the database, so I'll need it before the save is actually complete :)
class MyForm(forms.ModelForm):
def clean_file(self):
file = self.cleaned_data['file']
try:
if file:
file_type = file.content_type.split('/')[0]
print file_type
if len(file.name.split('.')) == 1:
raise forms.ValidationError(_('File type is not supported'))
if file_type in settings.TASK_UPLOAD_FILE_TYPES:
if file._size > settings.TASK_UPLOAD_FILE_MAX_SIZE:
raise forms.ValidationError(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(settings.TASK_UPLOAD_FILE_MAX_SIZE), filesizeformat(file._size)))
else:
raise forms.ValidationError(_('File type is not supported'))
except:
pass
return file
settings.py
TASK_UPLOAD_FILE_TYPES = ['pdf', 'vnd.oasis.opendocument.text','vnd.ms-excel','msword','application',]
TASK_UPLOAD_FILE_MAX_SIZE = "5242880"
You can use PIL or magic to read the few first bytes and get the MIME type that way. I wouldn't trust the content_type since anyone can fake an HTTP header.
Magic solution below. For a PIL implementation you can get an idea from django's get_image_dimensions.
import magic
def get_mime_type(file):
"""
Get MIME by reading the header of the file
"""
initial_pos = file.tell()
file.seek(0)
mime_type = magic.from_buffer(file.read(2048), mime=True)
file.seek(initial_pos)
return mime_type
File is the in-memory uploaded file in the view.
I'm using Django Rest Framework and this is the simplest way to determine content type/mime type:
file = request.data.get("file") # type(file) = 'django.core.files.uploadedfile.InMemoryUploadedFile'
print(file.content_type)
Let's say I have uploaded a JPEG image then my output would be:
image/jpeg
Let me know in the comments if this serves your purpose.
Need to override the save method in the model class
def save(self, *args, **kwargs):
if self.file and self.file.file:
try:#Need to add a try catch such that in case a file is not being uploaded, then the mime_type is not assigned
self.mime_type=self.file.file.content_type
except:
pass
Taking an assumption that our model has file column(FileField), and mime_type column (CharField)