Displaying a raw image using CBVs in Django - django

I want to do some image manipulation, but before I do I want to render the image. This is what I've tried, but it does not work. The page is blank, no errors, why?
class ImgThumbnail(DetailView):
queryset = Images.objects.all()
def render_to_response(self, context, **response_kwargs):
from PIL import Image
import requests
from io import BytesIO
response = requests.get('http://example.com/media/images/{}.jpg'.format(self.pk))
img = Image.open(BytesIO(response.content))
return HttpResponse(img, content_type='image/jpg')

You should use StreamingHttpResponse. In a way like:
(dynamic content type and content length as bonus)
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
from wsgiref.util import FileWrapper
from django.http import HttpResponse, StreamingHttpResponse
class ImgThumbnail(DetailView):
queryset = Images.objects.all()
def get(self, request, *args, **kwargs):
r = requests.get('http://example.com/media/images/{}.jpg'.format(self.pk))
if not r.status_code == 200:
return HttpResponse('', status=r.status_code)
wrapper = FileWrapper(StringIO(r.content))
response = StreamingHttpResponse(wrapper, content_type=r.headers.get('Content-Type'))
response['Content-Length'] = r.headers.get('Content-Length')
return response

DetailView doesn't have a render_to_response method, so there is no point in defining your own.
You're not using any of the functionality of DetailView here anyway. You should inherit from the base View class, and put your code in the get method.

Related

Serving a django model containing objects

I have following django model:
class Weather(models.Model):
lat_lng = gis_models.PointField()
raw_data = psql_fields.JSONField(null=True)
I have following view:
def weather(request):
data = WeatherModel.objects.all()
js_data = serializers.serialize('json', data)
return HttpResponse(js_data, content_type='application/json')
It throws error saying 'Point object is not json serializable.'
I want this function to return json.
Please help.
The default JSON serializer doesn't know how to serialize Point objects.
Derive your own from Django's encoder. You can also use JsonResponse for shorter code:
from django.contrib.gis.geos import Point
from django.core.serializers.json import DjangoJSONEncoder
from django.http import JsonResponse
class GeoJSONEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, Point):
return obj.coords
return super().default(obj)
def weather(request):
data = WeatherModel.objects.all()
return JsonResponse(data, encoder=GeoJSONEncoder)
You can use JsonResponse with values.
from django.http import JsonResponse
def weather(request):
data = list(WeatherModel.objects.all())
js_data = serializers.serialize('json', data)
return JsonResponse(data, safe=False) # or JsonResponse({'data': data})
Modifed answer from here.

How to view API data within a GET method that's created using POST method in Django (without a model)?

I have created a DRF API that allows me to submit an image using the POST method via POSTMAN. The image is not stored in the model. After it's submission, I want to view the image's name in the browser using the Django Rest Framework. After reading sources in the net, I found out that people used the GET method in order to view all the data in a model. However, I don't have a model (don't require it for now) so how can I implement this requirement?
The result should be something like this:
{
"image_name": <"name_of_the_image_stored">
}
This is what I had done so far:
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import ImgSerializer
from rest_framework import status
from rest_framework.parsers import FileUploadParser
class ImageAPI(APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
#key is 'image' when uploading in POSTMAN
file = self.request.data
data = file['image']
if data:
uploaded_file = data
fs = FileSystemStorage(location=settings.PRIVATE_STORAGE_ROOT)
filename = fs.save(uploaded_file.name, uploaded_file)
data = [{"image_name": filename}]
serializer = ImgSerializer(data, many = True).data
return Response(serializer, status = 200)
else:
return Response("Please upload an image", status = 400)
def get(self, request):
#What should I do here in order to view the submitted image above?
serializers.py:
from rest_framework import serializers
class ImgSerializer(serializers.Serializer):
image_name = serializers.CharField()
urls.py:
from upload.views import ImageAPI
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path("api/", ImageAPI.as_view(), name = "api"),
]
urlpatterns = format_suffix_patterns(urlpatterns)
First of all parser_classes should be an attribute of ImageAPI class, as I can see you've created it as a local variable, which won't do what you want. According to docs the request.data property should be a dictionary with a single key file containing the uploaded file. And regarding viewing the saved image, here you can find some ways to do that.
This is an example:
...
def get(self, request, *args, **kwargs):
# here I assume you've sent the name of the image using query params,
# but there are other better ways to do that
image_name = request.GET.get('image')
# here you should read the file from your storage
image_file = <read_image_file_by_given_name(image_name)>
return HttpResponse(image_file, content_type='image/png')

Django - how to write test for DRF ImageField

I have the following serializer:
from rest_framework.serializers import Serializer, ImageField
class MySerializer(Serializer):
avatar = ImageField()
how can I write a unit test for it?
I used the Django TestCase, but it raises an error.
from django.test import TestCase
class MySerializerTest(TestCase):
def setUp(self):
self.data = {}
...
def test_image(self):
import tempfile
self.data['avatar'] = tempfile.NamedTemporaryFile(suffix=".jpg").file
r_data = json.dumps(self.data)
j_data = json.loads(r_data)
serializer = MySerializer(data=j_data)
if not serializer.is_valid():
import pprint
pprint.pprint(serializer.errors)
self.assertEqual(serializer.is_valid(), True)
but it raises the following error:
TypeError: Object of type 'BufferedRandom' is not JSON serializable
What's my mistake? how can I write a test for image field?
I suggest to use SimpleUploadedFile class from django and create and image using Pillow package. See the example below.
from PIL import Image
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.utils.six import BytesIO
class MySerializerTest(TestCase):
...
def test_image(self):
image = BytesIO()
Image.new('RGB', (100, 100)).save(image, 'JPEG')
image.seek(0)
self.data['avatar'] = SimpleUploadedFile('image.jpg', image.getvalue())
serializer = MySerializer(data=self.data)
self.assertEqual(serializer.is_valid(), True)
Usually when you upload a file you would use the multipart request format, and the view would convert the image into an InMemoryUploadedFile object, and that gets passed into your serializer
So to fix your tests I'd recommend trying:
from PIL import Image
from tempfile import NamedTemporaryFile
from django.conf.files.uploadedfile import InMemoryUploadedFile
...
def test_image(self):
image = Image.new("RGB", (100, 100))
with NamedTemporaryFile(suffix=".png", mode="w+b") as tmp_file:
image.save(tmp_file, format="png")
tmp_file.seek(0)
byio = BytesIO(temp_file.read())
inm_file = InMemoryUploadedFile(
file=byio,
field_name="avatar",
name="testImage.png",
content_type="image/png",
size=byio.getbuffer().nbytes,
charset=None,
)
self.data['avatar'] = inm_file
serializer = MySerializer(data=self.data)
if not serializer.is_valid():
import pprint
pprint.pprint(serializer.errors)
self.assertEqual(serializer.is_valid(), True)
What this is doing is:
Create an image in memory using PIL.Image
Create a NamedTemporaryFile to store the Image data
Take the NamedTemporaryFile and read into a InMemoryUploadedFile
Pass this InMemoryUploadedFile into the serializer

Django how to call a function in another class from django admin section

hi recently I have implemented a temp django model and I want this to get populate when the user clicks it from django admin
this is the implementation in django admin
from django.contrib import admin
from polls.models import Poll
from polls.models import TempModel
from django.conf.urls import patterns
from django.http import HttpResponse
from test_data import TestData
from django.http import HttpResponse
from django.template import RequestContext, loader
from test_data import TestData
class TempModelAdmin(admin.ModelAdmin):
fields = ('permalink', )
def test(self):
x = TestData.get_test_data()
admin.site.register(Poll)
admin.site.register(TempModel, TempModelAdmin)
and this is the temporary class which I used to populate data
from models import TempModel
class TestData(object):
#classmethod
def get_test_data(self):
print "**********************************************"
print "get test data"
print "**********************************************"
list = []
for x in range(0,50):
str_val = str(x) + "djdj;djfhdfjiosdifj";
list.append(str_val)
temp_model = TempModel()
temp_model.permalink = str_val
temp_model.save()
print "=============================================="
print "Object Count"
print TempModel.objects.count()
print "=============================================="
return list
this is not getting called . Can anyone know the reason for this ?
Thank you in advace
You're making a class method with self, it takes an instance of type. Try changing method signature:
def get_test_data(cls):
I figured it out by doing this approach and it worked
class TempModelAdmin(admin.ModelAdmin):
fields = ('permalink', )
def __init__(self, *args, **kwargs):
super(TempModelAdmin, self).__init__(*args, **kwargs)
self.my_method()
def my_method(self):
print "*************----------------------------"
TestData.get_test_data()

ImportError for Django Piston handler that isn't tied to a model

I have created a custom handler (CustomHandler) that isn't tied to a model in the ORM and I think it's rigged up correctly, but I'm getting an ImportError: cannot import CustomHandler when trying to import it into my resources.py. Here is my setup:
custom_handlers.py:
from piston.handler import BaseHandler
class CustomHandler(BaseHandler):
allowed_methods = ('GET',)
def read(self, request):
return 'test'
resources.py:
from piston.resource import Resource
from piston.utils import rc
import simplejson as json
from api.authentication import DjangoAuthentication
from api.handlers import CustomHandler # ERROR THROWN HERE
auth = DjangoAuthentication(realm='...')
class JSONResource(Resource):
def determine_emitter(self, request, *args, **kwargs):
"""
Default to the json emitter.
"""
try:
return kwargs['emitter_format']
except KeyError:
pass
if 'format' in request.GET:
return request.GET.get('format')
return 'json'
def form_validation_response(self, e):
"""
Turns the error object into a serializable construct.
"""
resp = rc.BAD_REQUEST
json_errors = json.dumps(
dict(
(k, map(unicode, v))
for (k, v) in e.form.errors.iteritems()
)
)
resp.write(json_errors)
return resp
custom_handler = JSONResource(CustomHandler, authentication=auth)
urls.py:
from django.conf.urls.defaults import patterns, url
from api.resources import custom_handler
urlpatterns = patterns('',
url(r'^things/$', custom_handler),
)
UPDATE: I've tried manually compiling the pys into pycs with no luck. I also read this in Piston's docs:
When you create a handler which is tied to a model, Piston will
automatically register it (via a metaclass.)
But I can't find anything in the docs about creating a handler that isn't tied to a model, specifically how to register it.
Had to add from api.handlers.custom_handlers import CustomHandler to api/handlers/__init__.py