Send file to a different server - django

I have an upload url in my backend and i want to upload a file in another server.
My API view:
class AssessmentFileUpload(APIView):
parser_classes = (MultiPartParser, )
def post(self, request, format=None):
tenant = request.user.tenant.id
response = AssessmentFileUploadHelper(tenant).upload_file(request.FILES)
response_text = json.loads(response.text)
print(response_text)
if response.status_code == status.HTTP_201_CREATED:
return Response({"message": "success", "id": response_text.get('id')}, status=status.HTTP_201_CREATED)
return Response({"message": "failed"}, status=status.HTTP_400_BAD_REQUEST)
My class which sends request data to the other serve's url:
class AssessmentFileUploadHelper:
def __init__(self, tenant_id):
self.tenant_id = tenant_id
def upload_file(self, file):
print("FILE IS", file)
url = settings.ASSESSMENT_CONNECTION_SETTINGS["api_endpoint"] + "tenant/" + \
str(self.tenant_id) + "/fileupload/"
return RequestSender().send_request(url,None, file)
class RequestSender:
def __init__(self):
super().__init__()
def __get_authorized_header(self):
usernamepassword = settings.ASSESSMENT_CONNECTION_SETTINGS["userid"] + ":" + settings.ASSESSMENT_CONNECTION_SETTINGS["password"]
userAndPass = b64encode(usernamepassword.encode("utf-8")).decode("ascii")
authorization = "Basic " + userAndPass
headers = {'Authorization': authorization, "Content-Type": "application/json"}
return headers
def send_request(self, url, data, files=None):
json_data = json.dumps(data)
response = requests.post(url,
data=json_data,
headers=self.__get_authorized_header(),
files=files
)
return response
Now, the errors im getting is InMemoryUploadedFile is not json serilizaable . How to send request.FILES to that server ?

You neet to convert 'InMemoryUploadedFile' type to string:
str = request.FILES['file'].read().decode()

Related

How to handle a file form request and send by REST API

I'm trying to upload files, documents and images (once) using a Django form. The idea is to send it over an internal REST API that processes the file, stores it, and does other things.
The API is working but I can't successfully send the file over the API.
This is my code.
Here I process the form
def postNewFile(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = PostNewFile(request.POST, request.FILES)
# check whether it's valid:
if form.is_valid():
file_uploaded = request.FILES.get('file_uploaded')
file_name = file_uploaded.name
content_type = file_uploaded.content_type
formatType = form.cleaned_data['type']
category = form.cleaned_data['type']
description = form.cleaned_data['type']
response = postFile(file_uploaded, file_name, formatType, category, description, content_type)
if response == 0:
return HttpResponse('<H1>Enviado exitosamente</H1>')
else:
return HttpResponse('<H1>Error interno</H1>')
else:
print('No es valido')
return HttpResponse('<H1>Error en el formulario</H1>')
else:
return HttpResponse('<H1>Error en el formulario</H1>')
Here I make de API request
def postFile(doc, name, docType, category, description, content_type):
try:
url = URL_API+"file/"
payload={}
docs=[
('document',(name+'.'+docType, open(doc,'rb'),content_type))
]
headers = {
'Authorization': 'Bearer as',
'name': name,
'type': docType,
'category': category,
'description': description,
'content-type': content_type
}
response = requests.request("POST", url, headers=headers, data=payload, files=docs)
print(response.text)
return 0
except Exception as e:
print(e)
return -1

How to make Post request by list action for create function in viewsets in DRF

I want to send post request from testing. Its working for postman but it didnot work for my test case. How can I give the data by post request.
Views.py,
class PersonalInfoAPI(viewsets.ViewSet):
permission_classes = [IsOwnerPermission]
def get_object(self, pk):
obj = get_object_or_404(Employee.objects.all(), pk=pk)
self.check_object_permissions(self.request, obj)
return obj
def create(self, request):
personal_info = JSONParser().parse(request)
.....
return ...
test.py
url = reverse('employee1-list')
self.client = Client(HTTP_AUTHORIZATION='Token ' + token.key)
resp1 = self.client.post(url, {"data": {
"appraisal_master_id": 1,
"personal_info": {
"employee_id": 1,
"experience": "abcd",
"education": "Nonoooo"
}
}
}, format='json')
print(resp1)
self.assertEqual(resp1.status_code, 200)
I have got 400 error. Please, tell anyone how can I pass data im properway,..
I got solution. When I gave request which passes dictionary data. then, I coverted into json its working fine.
url = reverse('employee1-list')
self.client = Client(HTTP_AUTHORIZATION='Token ' + token.key)
resp1 = self.client.post(url, data=data, content_type="application/json")
print(resp1)
self.assertEqual(resp1.status_code, 201)

DRF File Upload, How can I solve File missing Error?

400 Error
{"detail":"Missing filename. Request should include a Content-Disposition header with a filename parameter."}
I want to upload file via DRF FileUploadParser
But Error occurs below
Bad Request: /api/activities/40/chapter/1/upload
[09/Nov/2021 16:44:33] "POST /api/activities/40/chapter/1/upload HTTP/1.1" 400 109
And my codes in views.py about that error are this.
class FileView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request, format=None, *args, **kwargs):
if 'file' not in request.FILES:
raise ParseError("Empty content")
f = request.FILES.get('file')
print(f)
print(dir(request))
print(request.__dict__)
addAttr = request.data.dict()
file_name = request.data['filename']
new_file_full_name = file_upload_path(file_name.name)
file_path = '/'.join(new_file_full_name.split('/')[0:-1])
#model Attr
addAttr['activityid'] = request.parser_context['kwargs']['pk']
addAttr['chapterid'] = request.parser_context['kwargs']['chapterid']
addAttr['filepath'] = file_path
addAttr['filename'] = file_name
addAttr['fileext'] = os.path.splitext(file_name.name)[1]
addAttr['create_date'] = datetime.datetime.now()
addAttrDict = QueryDict('', mutable=True)
addAttrDict.update(addAttr)
fileSerializer = ChapterfileSerializer(data = addAttrDict, files=request.FILES)
if fileSerializer.is_valid():
fileSerializer.save()
print(fileSerializer.data)
return Response(status=status.HTTP_201_CREATED)
else:
print(fileSerializer.errors)
return Response(fileSerializer.errors, status=status.HTTP_400_BAD_REQUEST)
If I add a parameter "filename", 500 error occured.
TypeError: post() missing 1 required positional argument: 'parameter'
[09/Nov/2021 16:48:35] "POST /api/activities/40/chapter/1/upload HTTP/1.1" 500 86716
ReactJS page sends File to my Django API Server.
activityid and chapterid are Board and Post ID.
SO, I need these insert to DB.
How can I solve this?
Use the FileUploadParser, it's all in the request. Use a put method instead, you'll find an example in the docs :)
class FileUploadAPIView(views.APIView):
parser_classes = (FileUploadParser,)
def put(self, request, filename, format=None):
file_obj = request.FILES['file']
# Do some stuff with the uploaded file
return Response({'details': 'Your file uploaded successfully.'}, status=204)

id parameter in get request

I am new to Django and a small detail has been bothering me.I have an api endpoint that returns the details of one patient. I have made a successful get request and tested on postman. It returns data for a particular patient with id = 996(I have hard coded the id). But I need to set it so it can pick the id from params in postman instead of the hard coded one here. How can I set params and append them on the url so that I use the id fed in postman instead of hard coding? Kindly assist
views.py
class PatientDetailsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
try:
result = {}
auth = cc_authenticate()
res = getPatientDetails(auth["key"], id)
result = res
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
error = getattr(e, "message", repr(e))
result["errors"] = error
result["status"] = "error"
return Response(result, status=status.HTTP_400_BAD_REQUEST)
api_service.py
def getPatientDetails(auth, id):
print("getting patientdetails from Callcenter")
try:
print(auth)
# print(url)
id= 996
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/patients/v1/details/?id={id}'
print(url)
res = requests.get(url, headers=headers)
print("returning patientdetails response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path("details/", views.PatientDetailsView.as_view(), name="patient_info"),
This is the code I needed
id = request.GET.get('<id>')

Vimeo 'Replace' API Endpoint Not Changing Thumbnail

I am using Vimeo's API for the users of my app to upload videos, or replace their existing video with a new one. I am using a Vimeo Client to help me make the calls in my Django Application. Uploading works without any issues, but when I try to replace an existing video with a new one, the thumbnail stays as the old video. If you play the video, it will play the new one, but the thumbnail never changes.
Model Method that Uploads/Replaces
def vimeo_upload(self):
media_file = self.video_file
if media_file and os.path.exists(media_file.path):
v = vimeo.VimeoClient(token=settings.VIMEO_ACCESS_TOKEN, key=settings.VIMEO_API_KEY,
secret=settings.VIMEO_API_SECRET)
if self.video_url is None:
try:
video_uri = v.upload(media_file.path)
except AssertionError as exc:
logging.error('Vimeo Error: %s Video: %s' % (exc, media_file.path))
else:
self.video_url = video_uri
else:
try:
v.replace(video_uri=self.video_url, filename=media_file.path)
except Exception as exc:
self.video_url = None
logging.error('Vimeo Replace Error: %s Video: %s' % (exc, media_file.path))
# set the video title, description, etc.
if self.video_url:
try:
# convert locale from en-us form to en
v.patch(self.video_url, data={'description': self.customer.full_name, })
except Exception as exc:
logging.error('Vimeo Patch Error: %s Video: %s' % (exc, media_file.path))
Vimeo Client Model, and UploadVideoMixin
class UploadVideoMixin(object):
"""Handle uploading a new video to the Vimeo API."""
UPLOAD_ENDPOINT = '/me/videos'
REPLACE_ENDPOINT = '{video_uri}/files'
def upload(self, filename, upgrade_to_1080=False):
"""Upload the named file to Vimeo."""
ticket = self.post(
self.UPLOAD_ENDPOINT,
data={'type': 'streaming',
'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
params={'fields': 'upload_link,complete_uri'})
return self._perform_upload(filename, ticket)
def replace(self, video_uri, filename, upgrade_to_1080=False):
"""Replace the video at the given uri with the named source file."""
uri = self.REPLACE_ENDPOINT.format(video_uri=video_uri)
ticket = self.put(
uri,
data={'type': 'streaming',
'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
params={'fields': 'upload_link,complete_uri'})
return self._perform_upload(filename, ticket)
def _perform_upload(self, filename, ticket):
"""Take an upload ticket and perform the actual upload."""
if ticket.status_code != 201:
raise UploadTicketCreationFailure(ticket, "Failed to create an upload ticket")
ticket = ticket.json()
# Perform the actual upload.
target = ticket['upload_link']
last_byte = 0
# Try to get size of obj by path. If provided obj is not a file path
# find the size of file-like object.
try:
size = os.path.getsize(filename)
with io.open(filename, 'rb') as f:
while last_byte < size:
try:
self._make_pass(target, f, size, last_byte)
except requests.exceptions.Timeout:
# If there is a timeout here, we are okay with it, since
# we'll check and resume.
pass
last_byte = self._get_progress(target, size)
except TypeError:
size = len(filename.read())
f = filename
while last_byte < size:
try:
self._make_pass(target, f, size, last_byte)
except requests.exceptions.Timeout:
# If there is a timeout here, we are okay with it, since
# we'll check and resume.
pass
last_byte = self._get_progress(target, size)
# Perform the finalization and get the location.
finalized_resp = self.delete(ticket['complete_uri'])
if finalized_resp.status_code != 201:
raise VideoCreationFailure(finalized_resp, "Failed to create the video")
return finalized_resp.headers.get('Location', None)
def _get_progress(self, upload_target, filesize):
"""Test the completeness of the upload."""
progress_response = self.put(
upload_target,
headers={'Content-Range': 'bytes */*'})
range_recv = progress_response.headers.get('Range', None)
_, last_byte = range_recv.split('-')
return int(last_byte)
def _make_pass(self, upload_target, f, size, last_byte):
"""Make a pass at uploading.
This particular function may do many things. If this is a large upload
it may terminate without having completed the upload. This can also
occur if there are network issues or any other interruptions. These
can be recovered from by checking with the server to see how much it
has and resuming the connection.
"""
response = self.put(
upload_target,
timeout=None,
headers={
'Content-Length': str(size),
'Content-Range': 'bytes: %d-%d/%d' % (last_byte, size, size)
}, data=f)
if response.status_code != 200:
raise VideoUploadFailure(response, "Unexpected status code on upload")
class VimeoClient(ClientCredentialsMixin, AuthorizationCodeMixin, UploadMixin):
"""Client handle for the Vimeo API."""
API_ROOT = "https://api.vimeo.com"
HTTP_METHODS = set(('head', 'get', 'post', 'put', 'patch', 'options', 'delete'))
ACCEPT_HEADER = "application/vnd.vimeo.*;version=3.2"
USER_AGENT = "pyvimeo 0.3.10; (http://developer.vimeo.com/api/docs)"
def __init__(self, token=None, key=None, secret=None, *args, **kwargs):
"""Prep the handle with the authentication information."""
self.token = token
self.app_info = (key, secret)
self._requests_methods = dict()
# Make sure we have enough info to be useful.
assert token is not None or (key is not None and secret is not None)
# Internally we back this with an auth mechanism for Requests.
#property
def token(self):
return self._token.token
#token.setter
def token(self, value):
self._token = _BearerToken(value) if value else None
def __getattr__(self, name):
"""This is where we get the function for the verb that was just
requested.
From here we can apply the authentication information we have.
"""
if name not in self.HTTP_METHODS:
raise AttributeError("%r is not an HTTP method" % name)
# Get the Requests based function to use to preserve their defaults.
request_func = getattr(requests, name, None)
if request_func is None:
raise AttributeError(
"%r could not be found in the backing lib" % name
)
#wraps(request_func)
def caller(url, jsonify=True, **kwargs):
"""Hand off the call to Requests."""
headers = kwargs.get('headers', dict())
headers['Accept'] = self.ACCEPT_HEADER
headers['User-Agent'] = self.USER_AGENT
if jsonify \
and 'data' in kwargs \
and isinstance(kwargs['data'], (dict, list)):
kwargs['data'] = json.dumps(kwargs['data'])
headers['Content-Type'] = 'application/json'
kwargs['timeout'] = kwargs.get('timeout', (1, 30))
kwargs['auth'] = kwargs.get('auth', self._token)
kwargs['headers'] = headers
if not url[:4] == "http":
url = self.API_ROOT + url
response = request_func(url, **kwargs)
if response.status_code == 429:
raise APIRateLimitExceededFailure(
response, 'Too many API requests'
)
return response
return caller
class _BearerToken(requests.auth.AuthBase):
"""Model the bearer token and apply it to the request."""
def __init__(self, token):
self.token = token
def __call__(self, request):
request.headers['Authorization'] = 'Bearer ' + self.token
return request