代码之家  ›  专栏  ›  技术社区  ›  devmrh

Django验证并将任何图像转换为jpeg,然后保存

  •  0
  • devmrh  · 技术社区  · 6 年前

    我在模型中有图像字段类型文件…我要检查用户上载的文件是否为图像。如果要将其图像转换为“jpeg”格式,以减小大小和安全性。我该怎么做?

    相关视图:

    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)
    

    模型:

    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])
    

    自定义路径:

    # 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)
    

    ‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌_

    错误日志:

    (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]
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   Satendra    6 年前

    建议使用 ImageField ,如果您只想上载 图像,它自动验证上载的对象是有效的图像。

    重写的保存方法 Product 型号和用途 Image 类别 PIL 要转换为的包 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)