Could I use InMemoryUploadedFile directly to upload Image to Imgur? - python

I have some problems about uploading image to Imgur by using Django.
I have finished that Image File uploaded from react and delivered File data to backend via Axios.
But the object I got from the request.data in Python backend is InMemoryUploadedFile.
I don't want to store any image files in my disk.
Could I use directly this file which is a InMemoryUploadedFile type to upload by Imgur upload function upload_from_path?
If so, how can I do?
Here are my code,
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.response import Response
from django.contrib.auth.models import User
from base.models import InCome, IncomeMoneyCategory, IncomeContributeContext,OutcomeMoneyCategory, OutcomeContributeContext, Member, Student, OutCome
from django.db.models import F, Sum
from base.serializers import IncomeSerializer, OutcomeSerializer
from rest_framework import status
from datetime import datetime
import configparser
import base.config as env
import os
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings
from imgurpython import ImgurClient
#api_view(['POST'])
def upload_image(request):
data = request.data
print(data)
album = env.IMGUR_ALBUM
print(data['image'])
image=data['image']
print("--")
print(type(image))
image_path=image
config = configparser.ConfigParser()
path = '/'.join((os.path.abspath(__file__).replace('\\', '/')).split('/')[:-1])
config.read(os.path.join(path, 'auth.ini'))
#config.read('auth.ini')
client_id = config['credentials']['client_id']
client_secret = config['credentials']['client_secret']
refresh_token = config['credentials']['refresh_token']
access_token = config['credentials']['access_token']
client = ImgurClient(client_id,client_secret, refresh_token)
client.set_user_auth(access_token, refresh_token)
if client:
config={
'album':album,
'name':'Ezra',
'title':'Test',
'description': 'Test {0}'.format(datetime.now())
}
print("Uploading image")
image = client.upload_from_path(str(image_path),config=config,anon=False)
print(image['link'])
print("Done")
return image
else:return "Error"
The type of image is <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>.
But the first one parameter in the function ImgurClient.upload_from_path of imgurpython package needs the file name to upload.
So when I execute this code, I'll get this Error:
No such file or directory:...
Hope someone can help me to solve it, and sorry for my poor English.
Thank you for reading.

I have solved it later.
I used default_storage to save the file and gave the directory as the first parameter in the upload_from_path method.
After uploading to Imgur, I deleted the files and return link back.
Here is my code:
def upload_image(request):
data = request.data
album = env.IMGUR_ALBUM
image=data['image']
file = data['image']
filename = default_storage.save(file.name, ContentFile(file.read()))
config = configparser.ConfigParser()
path = '/'.join((os.path.abspath(__file__).replace('\\', '/')).split('/')[:-1])
config.read(os.path.join(path, 'auth.ini'))
client_id = config['credentials']['client_id']
client_secret = config['credentials']['client_secret']
refresh_token = config['credentials']['refresh_token']
access_token = config['credentials']['access_token']
client = ImgurClient(client_id,client_secret, refresh_token)
client.set_user_auth(access_token, refresh_token)
if client:
config={
'album':album,
'name':'Ezra',
'title':'Test',
'description': 'Test {0}'.format(datetime.now())
}
print("Uploading image")
image = client.upload_from_path(settings.MEDIA_ROOT+'/'+filename,config=config,anon=False)
print("Done")
default_storage.delete(filename)
return Response(image['link'])
else:return "Error"

Related

How can I pass in url arguments to an APIRequestFactory put request?

I have been trying for hours but cannot figure out how to pass a url argument through an APIRequestFactory put request. I have tried it through Postman when running my server and the url variable is passed just fine, but when I run it in my tests it stops working.
What I mean is that when I send a Postman PUT request to '/litter/1/' it will successfully take in the 1 as the variable litterId since my url is setup like this
path('litter/', include('apps.litter.urls')),
and
path('<int:litterId>/', LitterView.as_view(), name='litter-with-id')
But when I try and send an APIRequestFactory put request to that same url, for some reason the 1 will not go through as the litterId anymore.
Some relevant pieces of code...
My top level url.py
from rest_framework.authtoken import views
from apps.litter.views import LitterView
urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('apps.my_auth.urls')),
path('litter/', include('apps.litter.urls')),
]
This is my app specific urls.py
from .views import LitterView
urlpatterns = [
path('', LitterView.as_view(), name='standard-litter'),
path('<int:litterId>/', LitterView.as_view(), name='litter-with-id'),
]
Here is my views.py
import json
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.views.decorators.csrf import csrf_exempt
from rest_framework import authentication, permissions
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db import models
from .models import Litter
from .serializers import LitterSerializer
##csrf_exempt
class LitterView(APIView):
"""
View for litter related requests
* Requres token auth
"""
permission_classes = (IsAuthenticated,)
authentication_classes = [authentication.TokenAuthentication]
renderer_classes = [JSONRenderer]
def put(self, request, litterId=0):
"""
Updates an old litter
"""
try:
litterModel = Litter.objects.get(user=request.user, id=litterId)
except Litter.DoesNotExist:
returnData = {'status': 'fail',
'error': 'Could not find object with that id.'}
return Response(returnData)
serializer_class = LitterSerializer
serialized = LitterSerializer(litterModel, data=request.data)
if serialized.is_valid():
litterModel = serialized.save()
returnData = {'status': 'okay',
'litter': [serialized.data]}
return Response(returnData)
else:
return Response(serialized.errors, status=400)
And here is the relevant test.
def test_easy_successful_put_type(self):
"""
Testing a simple put
"""
user = UserFactory()
amount = 40
amountChange = 20
litter = LitterFactory(user=user, amount=amount)
data = {'typeOfLitter': litter.typeOfLitter,
'amount': litter.amount + amountChange,
'timeCollected': litter.timeCollected}
url = '/litter/' + str(litter.id) + '/'
request = self.factory.put(url, data, format='json')
force_authenticate(request, user=user)
view = LitterView.as_view()
response = view(request).render()
responseData = json.loads(response.content)
No matter what I do, I cannot get the int:litterId to get passed in, the put function always has the default value of 0. Any help would be greatly appreciated.
Your problem is here:
response = view(request).render()
You are manually passing the request to the view, also not passing the kwarg litterId, instead use APIClient and make a put request to the url. First import the required modules:
from django.urls import reverse
from rest_framework.test import APIClient
then:
user = UserFactory()
amount = 40
amountChange = 20
litter = LitterFactory(user=user, amount=amount)
data = {
'typeOfLitter': litter.typeOfLitter,
'amount': litter.amount + amountChange,
'timeCollected': litter.timeCollected
}
url = reverse('litter-with-id', kwargs={'litterId': litter.id})
client = APIClient()
client.force_authenticate(user=user)
response = client.put(url, data, format='json')

get Json data from request with Django

I'm trying to develop a very simple script in Django, I'd collect a Json data from the request and then store all data in the database.
I developed one python script that I'm using to send the Json data to the Django view, but I'm doing something wrong and I can't understand what, because every time that I run it,I've got "Malformed data!".
Can someone helps me? what am I doing wrong?
Sender.py
import json
import urllib2
data = {
'ids': ["milan", "rome","florence"]
}
req = urllib2.Request('http://127.0.0.1:8000/value/')
req.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(req, json.dumps(data))
Django view.py
from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
import json
from models import *
from django.http import StreamingHttpResponse
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def value(request):
try:
data = json.loads(request.body)
label = data['label']
url = data ['url']
print label, url
except:
return HttpResponse("Malformed data!")
return HttpResponse("Got json data")
Your dictionary "data" in sender.py contains only one value with key "ids" but in view.py you are trying to access keys "label" and "url" in this parsed dictionary.

Getting 403 response in test script using Django REST and OAuth2

I am getting a 403 response in my test script which uses Django REST and OAuth2. I am using force_authenticate.
In urls.py:
urlpatterns = [
url(r'^user-id/$', views.UserIDView.as_view(), name='user-id'),
...
In views.py:
from oauth2_provider.ext.rest_framework import TokenHasReadWriteScope
class StdPerm(TokenHasReadWriteScope):
pass
StdPermClasses = (IsAuthenticated, StdPerm)
class UserIDView(APIView):
permission_classes = StdPermClasses
renderer_classes = (JSONRenderer,)
def get(self, request, format=None):
return Response({'id': request.user.id})
In tests.py:
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
class CreateUserTest(APITestCase):
def setUp(self):
self.user = User.objects.create_user('daniel', 'daniel#test.com',
password='daniel')
self.user.save()
def test_get_user_id(self):
self.client.login(username='daniel', password='daniel')
self.client.force_authenticate(user=self.user)
response = self.client.get(reverse('user-id'))
self.assertEqual(response.status_code, status.HTTP_200_OK)
Usually I use curl which works no problem:
curl -X GET "http://127.0.0.1:8000/user-id/" -H "Authorization: Bearer b3SlzXlpRSxURyh2BltwdHmhrlqNyt"
Update I changed some lines in test_get_user_id:
token = Token.objects.create(user=self.user)
self.client.force_authenticate(user=self.user, token=token)
Now I get the error:
assert False, ('TokenHasScope requires either the' AssertionError:
TokenHasScope requires either the`oauth2_provider.rest_framework
.OAuth2Authentication` authentication class to be used.
I found a solution to this problem. Basically my code was missing two things, namely the OAuth2 application record and an access token specific to OAuth2. I added the following to setUp:
app = Application(
client_type='confidential',
authorization_grant_type='password',
name='MyAppTest',
user_id=1
)
app.save()
...for generating a suitable access token:
app = Application.objects.get(name='MyAppTest')
token = generate_token()
expires = now() + timedelta(seconds=oauth2_settings. \
ACCESS_TOKEN_EXPIRE_SECONDS)
scope = 'read write'
access_token = AccessToken.objects.create(
user=self.user,
application=app,
expires=expires,
token=token,
scope=scope
)
...and then to use the token:
self.client.force_authenticate(user=self.user, token=access_token)
The import section ended up like so:
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from oauth2_provider.settings import oauth2_settings
from oauthlib.common import generate_token
from oauth2_provider.models import AccessToken, Application
from django.utils.timezone import now, timedelta
This worked for me
from oauth2_provider.settings import oauth2_settings
from oauth2_provider.models import get_access_token_model,
get_application_model
from django.contrib.auth import get_user_model
from django.utils import timezone
from rest_framework.test import APITestCase
Application = get_application_model()
AccessToken = get_access_token_model()
UserModel = get_user_model()
class Test_mytest(APITestCase):
def setUp(self):
oauth2_settings._SCOPES = ["read", "write", "scope1", "scope2", "resource1"]
self.test_user = UserModel.objects.create_user("test_user", "test#example.com", "123456")
self.application = Application.objects.create(
name="Test Application",
redirect_uris="http://localhost http://example.com http://example.org",
user=self.test_user,
client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
)
self.access_token = AccessToken.objects.create(
user=self.test_user,
scope="read write",
expires=timezone.now() + timezone.timedelta(seconds=300),
token="secret-access-token-key",
application=self.application
)
# read or write as per your choice
self.access_token.scope = "read"
self.access_token.save()
# correct token and correct scope
self.auth = "Bearer {0}".format(self.access_token.token)
def test_success_response(self):
url = reverse('my_url',)
# Obtaining the POST response for the input data
response = self.client.get(url, HTTP_AUTHORIZATION=self.auth)
# checking wether the response is success
self.assertEqual(response.status_code, status.HTTP_200_OK)
Now everything will work as expected. Thanks

How can I convert a HTML Page to PDF using Django

I have a web app in Django. It's a plataform to store bills and invoices. Now i'm trying to export those bills un PDF.
I'm using xhtml2pdf but it's not working.
I'm using this code for testing:
http://obroll.com/generate-pdf-with-xhtml2pdf-pisa-in-django-examples/
It doesnt give any errors but doesnt generate the PDF documentos.
Try using this code. It works for me.
Change "template_testing.html" for your template and add your data to render on "data = {}"
views.py:
import os
from django.conf import settings
from django.http import HttpResponse
from django.template import Context
from django.template.loader import get_template
import datetime
from xhtml2pdf import pisa
def generate_PDF(request):
data = {}
template = get_template('template_testing.html')
html = template.render(Context(data))
file = open('test.pdf', "w+b")
pisaStatus = pisa.CreatePDF(html.encode('utf-8'), dest=file,
encoding='utf-8')
file.seek(0)
pdf = file.read()
file.close()
return HttpResponse(pdf, 'application/pdf')

protecting user uploaded files django

How can I allow users to upload files to their own, user designated folder, and only see files that they have uploaded? I am using django file-transfer. Currently it gives me a choice of what file to put the media in, but I can put it in any user's file and view every user's media. Here is my uploads/models.py:
from django.db import models
from django.contrib.auth.models import User, UserManager
def uploadmodel_file_upload_to(instance, filename):
print 'instance.user.username = '+ str(instance.user.username)
return 'uploads/%s/%s' % (instance.user.username, filename)
class UploadModel(models.Model):
user = models.ForeignKey('auth.user')
file = models.FileField(upload_to=uploadmodel_file_upload_to)
uploadmodel_file_upload_to returns a relative path. To build the full path, django prepends settings.MEDIA_ROOT. MEDIA_ROOT is supposed to be public readable.
So we want to save the file outside MEDIA_ROOT. Add something like this to settings.py:
import os.path
PROJECT_ROOT=os.path.abspath(os.path.dirname(__file__))
PROTECTED_MEDIA_ROOT=os.path.join(PROJECT_ROOT, 'protected_uploads')
Now you can update uploadmodel_file_upload_to to return an absolute path:
def uploadmodel_file_upload_to(instance, filename):
return '%s/%s/%s' % (settings.PROTECTED_MEDIA_ROOT, instance.user.username,
filename)
Now that the files are saved in /project/path/protected_uploads, we need to add a view to serve it, for example:
import os
import mimetypes
from django import shortcuts
from django import http
from django.conf import settings
from django.views.static import was_modified_since
from django.utils.http import http_date
from .models import *
def serve_upload(request, upload_id):
upload = shortcuts.get_object_or_404(UploadModel, pk=upload_id)
fullpath = upload.file.path
if request.user != upload.user:
return http.HttpResponseForbidden()
statobj = os.stat(fullpath)
mimetype, encoding = mimetypes.guess_type(fullpath)
mimetype = mimetype or 'application/octet-stream'
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
statobj.st_mtime, statobj.st_size):
return http.HttpResponseNotModified(mimetype=mimetype)
response = http.HttpResponse(open(fullpath, 'rb').read(), mimetype=mimetype)
response["Last-Modified"] = http_date(statobj.st_mtime)
response["Content-Length"] = statobj.st_size
if encoding:
response["Content-Encoding"] = encoding
return response
And a URL:
url(r'serve_upload/(?P<upload_id>\d+)/$', 'serve_upload'),

Categories