Skip to content

Instantly share code, notes, and snippets.

@frnhr
Forked from ObserverOfTime/svgimagefield.py
Last active October 28, 2020 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frnhr/65b64df781c07de2ce77ca84f5c12f15 to your computer and use it in GitHub Desktop.
Save frnhr/65b64df781c07de2ce77ca84f5c12f15 to your computer and use it in GitHub Desktop.
A form field to handle validation of image + svg, Django 3.1
from django.core import validators
from lxml import etree
from django.core.exceptions import ValidationError
from django.forms import ImageField
# monkeypatch allowed file extensions:
_original = validators.get_available_image_extensions
validators.get_available_image_extensions = lambda: _original() + ["svg"]
class SVGImageField(ImageField):
"""A Django ImageField that accepts SVG images."""
def to_python(self, data):
"""
Check that the file-upload field data contains a valid image
(GIF, JPG, PNG, etc. -- whatever Pillow supports) or a SVG image.
"""
file = super(ImageField, self).to_python(data) # skip a MRO level
if file is None:
return None
try:
file = super().to_python(data)
except ValidationError as err:
# add a workaround to handle svg images
if not self.is_svg(file):
raise ValidationError(
self.error_messages['invalid_image'],
code='invalid_image',
) from err
file = super(ImageField, self).to_python(data)
file.content_type = 'image/svg+xml'
return file
def run_validators(self, value: str):
if not self.is_svg(value):
return super(ImageField, self).run_validators(value)
return super().run_validators(value)
@staticmethod
def is_svg(file):
"""Check if the provided file is a SVG image."""
if file is None:
return False
if hasattr(file, 'seek'):
file.seek(0)
opened = False
else:
file = open(file)
opened = True
try:
part_of_svg_tag = '{http://www.w3.org/2000/svg}'
tree = etree.iterparse(file)
first_tag = next(tree)[1].tag
return part_of_svg_tag in first_tag
except etree.ParseError:
return False
finally:
if opened:
file.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment