Issue
i have image field type file in model ...i want check user uploaded file is image or not if its image i want convert it to "jpeg" format for reduce size and security purposes.. how can i do that ?
related view:
class StoreCreateAPIView(generics.CreateAPIView):
parser_classes = (MultiPartParser, FormParser)
permission_classes = [IsAuthenticated, IsSuperUserOrAdmin]
def post(self, request, *args, **kwargs):
if request.method == 'POST':
file_serial = ProductSerializer(data=request.data, context={"request": request})
if file_serial.is_valid():
file_serial.save(author_id=request.user.id)
model:
def validate_image(image):
if not image.is_image():
raise ValidationError('File should be image.')
file_size = image.file.size
limit_kb = 200
if file_size > limit_kb * 1024:
raise ValidationError("Max size of file is {} KB".format(limit_kb))
# save the uploaded file in user directory
def upload_to_custom_p(instance, filename):
name = instance.title
user_id = str(instance.author.id)
filename = filename.lower()
return 'Product/img/user_{0}/{1}/{2}'.format(user_id, name, filename)
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
title = models.CharField(max_length=200)
full_description = models.TextField(null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
publish = models.BooleanField(default=False)
draft = models.BooleanField(default=False)
slug = models.SlugField(allow_unicode=True, null=True, blank=True)
image = models.FileField(upload_to=upload_to_custom_p, null=True, blank=True,validators=[validate_image])
custom_path:
# save the uploaded file in user directory
def upload_to_custom_p(instance, filename):
name = instance.title
user_id = str(instance.author.id)
filename = filename.lower()
return 'Product/img/user_{0}/{1}/{2}'.format(user_id, name, filename)
error log:
(uenv) [deb@arch academy]$ python3 manage.py runserver
Performing system checks...
/upload/upload/aa.mp4
System check identified no issues (0 silenced).
July 22, 2018 - 15:52:01
Django version 2.0.7, using settings 'academy.settings'
Starting ASGI/Channels version 2.1.1 development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
2018-07-22 15:52:01,540 - INFO - server - HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2018-07-22 15:52:01,541 - INFO - server - Configuring endpoint tcp:port=8000:interface=127.0.0.1
2018-07-22 15:52:01,543 - INFO - server - Listening on TCP address 127.0.0.1:8000
Internal Server Error: /api/v1/store/view/make/
Traceback (most recent call last):
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 481, in _save
fh = fp.fileno()
io.UnsupportedOperation: fileno
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 940, in create
instance = ModelClass.objects.create(**validated_data)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/db/models/query.py", line 417, in create
obj.save(force_insert=True, using=self.db)
File "/home/deb/PycharmProjects/ac2/academy/api/v1/store/models.py", line 42, in save
image.save(image_io, format='JPEG')
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/Image.py", line 1950, in save
save_handler(self, fp, filename)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/JpegImagePlugin.py", line 762, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 496, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/home/deb/PycharmProjects/ac2/academy/api/v1/store/views.py", line 269, in post
file_serial.save(author_id=request.user.id)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 214, in save
self.instance = self.create(validated_data)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 957, in create
raise TypeError(msg)
TypeError: Got a `TypeError` when calling `Product.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Product.objects.create()`. You may need to make the field read-only, or override the ProductSerializer.create() method to handle this correctly.
Original exception was:
Traceback (most recent call last):
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 481, in _save
fh = fp.fileno()
io.UnsupportedOperation: fileno
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/rest_framework/serializers.py", line 940, in create
instance = ModelClass.objects.create(**validated_data)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/django/db/models/query.py", line 417, in create
obj.save(force_insert=True, using=self.db)
File "/home/deb/PycharmProjects/ac2/academy/api/v1/store/models.py", line 42, in save
image.save(image_io, format='JPEG')
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/Image.py", line 1950, in save
save_handler(self, fp, filename)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/JpegImagePlugin.py", line 762, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
File "/home/deb/PycharmProjects/ac2/uenv/lib/python3.6/site-packages/PIL/ImageFile.py", line 496, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'
[2018/07/22 15:52:32] HTTP POST /api/v1/store/view/make/ 500 [0.42, 127.0.0.1:52918]
Solution
It's recommended using
ImageField
, If you just want to upload an image, It auto validates that the uploaded object is a valid image.
Override save method of Product
model and use Image
class of PIL
package to convert it to JPEG
from django.core.files.base import ContentFile
from PIL import Image
from io import BytesIO
class Product(models.Model):
# attribute lies here
...
def save(self, *args, **kwargs):
if self.image:
filename = "%s.jpg" % self.image.name.split('.')[0]
image = Image.open(self.image)
# for PNG images discarding the alpha channel and fill it with some color
if image.mode in ('RGBA', 'LA'):
background = Image.new(image.mode[:-1], image.size, '#fff')
background.paste(image, image.split()[-1])
image = background
image_io = BytesIO()
image.save(image_io, format='JPEG', quality=100)
# change the image field value to be the newly modified image value
self.image.save(filename, ContentFile(image_io.getvalue()), save=False)
super(Product, self).save(*args, **kwargs)
Answered By - Satendra
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.