Using django rest framework to send an image - django

I want to use DRF to send an image to response to a certain url, for this purpose I have written these codes:
#Renderer class
class ImageRenderer(renderers.BaseRenderer):
media_type = 'image/png'
format = 'image'
def render(self, data, media_type=None, renderer_context=None):
return data
#view class
class ShowImage(APIView):
renderer_classes = (ImageRenderer,)
def get(self, request, format=None):
print ('format', format)
if format == 'image':
image_file = open('path_to_image', 'rb')
response = HttpResponse(image_file, content_type='image/png')
response['Content-Disposition'] = 'attachment; filename={}'.format('image_filename')
#urls.py
urlpatterns = format_suffix_patterns([
url(r'image/?$', views.ShowImage.as_view())
])
But my problem is that always the input format is None although the request.accepted_media_type shows me image/png
I tried these requests using httpie:
http -vj 127.0.0.1:8000/api/image Accept:image/png
http -vj 127.0.0.1:8000/api/image.image Accept:image/png
But I could not get the format I expected. What is my mistake in using DRF?

Related

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)

How to pass data saved from a POST method to the GET method using REST API Django (without a model)?

I have created an API that allows me to upload an image using the POST method in POSTMAN. After submission, I want to display that image name after making a GET request. I am not using any model and I don't intend to grab the image from the directory it is stored in; since I will be uploading images in a server later.
I have looked at multiple sources. A few examples are this, and this.
This is my current code so far but not successful:
views.py:
class API(APIView):
parser_classes = (MultiPartParser,)
def get(self, request, *args, **kwargs):
name = self.request.GET.get('image')
if name:
return Response({"img_name": name}, status=200)
return Response({"img_name" : None}, status = 400)
def post(self, request):
file = self.request.data
img_file = file['image'] #store the image data in this variable
if img_file:
uploaded_file = img_file
img = [{"image_name": uploaded_file}]
serializer = ImgSerializer(img, many = True).data
return Response(serializer, status = 200)
else:
return Response("Please upload", status = 400)
serializers.py:
from rest_framework import serializers
class ImgSerializer(serializers.Serializer):
image_name = serializers.CharField()
My expected result within GET request should be like this:
{'image_name' : 'image_name_from_POST_Request'}
But I am getting this result instead:
None
How can I pass data from the POST request to the GET request using Django's rest framework? Is there an efficient way to deploy this requirement without using a model?
I figured it out. I just created a JSON file in the POST method and stored the necessary data in it. Finally, in order to view the data within the GET method, I opened the file and returned it as a Response.
views.py:
class API(APIView):
parser_classes = (MultiPartParser,)
def get(self, request):
with open('data.txt') as json_file:
data = json.load(json_file)
if data:
return Response(data, status=200)
return Response({"name" : None}, status = 400)
def post(self, request):
posted_file = self.request.data
img_file = posted_file['image']
if img_file:
uploaded_file = img_file
data = [{"image_name": uploaded_file}]
json_data = {"image_name": uploaded_file}
data = {}
data['key'] = []
data['key'].append(json_data)
with open('data.txt', 'w') as outfile:
json.dump(image, outfile)
serializer = ImgSerializer(image, many = True).data
return Response(serializer, status = 200)
else:
return Response(serializer.errors, status = 400)

How to POST image to django rest API

I am not too practiced in handling image files, and I am very confused about posting and handling an image using my django REST API. I am using a python script as client just for testing (will be ios app eventually).
Anyone who can help me receive an image file, and save it locally on the server would be greatly appreciated.
Client:
i = Image.open('image.jpeg')
upload = {
'id': 3,
'picture': i
}
r = requests.post(ip, data=upload, stream=True)
print(r.text)
Server:
class Picture_Upload(APIView):
def post(self, request):
f = request.data['picture']
return Response(f.content)
You might want to use MultiPartParser to parse the form data so that you can read it on your APIView, and surely that we have to send data as multipart/form-data. Like so:
upload = {
'picture': open('image.jpeg', 'rb')
}
data = {
'id': 3
}
resp = requests.post('/upload_url/', files=upload, data=data)
and your view:
class Picture_Upload(APIView):
parser_classes = (MultiPartParser, FormParser, )
def post(self, request):
picture = request.data['picture']
id = request.data['id']
# Use your model to handle the uploaded file
return Response(status=200)

How to set Content-Disposition header using Django Rest Framework

I am serving an image using the Django REST framework. Unfortunately it downloads instead of displays. I guess I have to set the header Content-Disposition = 'inline'. How do I do this in the View or the Renderer?
class ImageRenderer(renderers.BaseRenderer):
media_type = 'image/*'
format = '*'
charset = None
render_style = 'binary'
def render(self, data, media_type=None, renderer_context=None):
return data
class ImageView(APIView):
renderer_classes = (ImageRenderer, )
def get(self, request, format=None):
image=MyImage.objects.get(id=1)
image_file = image.thumbnail_png.file
return Response(image)
According to this page in the Django docs, you can set the Content-Disposition header in this way:
response = Response(my_data, content_type='image/jpeg')
response['Content-Disposition'] = 'attachment; filename="foo.jpeg"'

Retrieving images from GridFS using django-tastypie-mongoengine

I have a project in Django, and I'm using mongoengine to save images into a Mongo database using GridFSStorage.
All ok so far, but the problem is... when trying to retrieve the images via http request, with a REST API made with django-tastypie-mongoengine, I get back a json object like this:
{"file": "<GridFSProxy: 516ed7cf56ba7d01eb09f522>", "id": "516ed7cf56ba7d01eb09f524", "resource_uri": "/api/v1/pic/516ed7cf56ba7d01eb09f524/"}
Does anybody know how could I get the file from GridFS via http request?
Many thanks!
You'll need to write your own view, but you can make it seem like it's part of the API. First, the view:
def api_image(pk):
obj = get_object_or_404(Model, pk=pk)
image_file = obj.file
return Response(image_file.read(),
mime_type='image/png') # or whatever the MIME type is
Then, you can map it in your urls.py:
url('^/api/v1/pic/(?P<pk>\w+)/file/$', api_image)
And to make sure tastypie shows what you want in the output:
def dehydrate_file(self, bundle):
return '/api/v1/pic/%s/file/' % (bundle.obj.id)
Just make sure the fake API view appears ahead of your actual API definitions, and you should be all set!
Paul's hint was very useful. Here i have implemented this completely in tastypie manner for uploading and downloading images.
Here you go..
1. Overriding deseriazer to support 'multipart'.
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
2. Model class
class Research(Document):
user = ReferenceField(User)
academic_year = StringField(max_length=20)
subject = StringField(max_length=150)
topic = StringField(max_length=50)
pub_date = DateTimeField()
authored = StringField(max_length=20)
research_level = StringField(max_length=20)
paper_presented = BooleanField()
thesis_written = BooleanField()
proof_image = ImageField()
3. Resource class
class ResearchResource(MultipartResource, MongoEngineResource):
class Meta:
queryset = Research.objects.all()
list_allowed_methods = ['get','post']
resource_name = 'research'
authentication = SessionAuthentication()
authorization = Authorization()
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/$" % self._meta.resource_name,
self.wrap_view('dispatch_list'), name="api_dispatch_list"),
#url to download image file.
url(r"^(?P<resource_name>%s)/(?P<pk>\w+)/file/$"% self._meta.resource_name,
self.wrap_view('get_image'), name="api_get_image"),
]
#Preparing image url dynamically
def dehydrate_proof_image(self, bundle):
return '/api/v1/%s/%s/file/' % (self._meta.resource_name,bundle.obj.id)
#view will call based on image url to download image.
def get_image(self, request, **kwargs):
obj = Research.objects.get(id=kwargs['pk'])
image_file = obj.proof_image
return HttpResponse(image_file.read(), content_type="image/jpeg"))
Hope this will be very useful for everyone in future. :)