diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index afe047d..9ac3f29 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,30 +13,8 @@ jobs:
matrix:
os: [ubuntu-20.04]
python-version: [python3.9, python3.8]
- django-version: [django3.2, django3.1, django3.0, django2.2, django2.1, django2.0]
- drf-version: [drf3.12, drf3.11, drf3.10, drf3.09]
- exclude:
- - os: ubuntu-20.04
- django-version: django3.2
- drf-version: drf3.10
- - os: ubuntu-20.04
- django-version: django3.1
- drf-version: drf3.10
- - os: ubuntu-20.04
- django-version: django3.2
- drf-version: drf3.09
- - os: ubuntu-20.04
- django-version: django3.1
- drf-version: drf3.09
- - os: ubuntu-20.04
- django-version: django3.0
- drf-version: drf3.09
- - os: ubuntu-20.04
- django-version: django2.1
- drf-version: drf3.12
- - os: ubuntu-20.04
- django-version: django2.0
- drf-version: drf3.12
+ django-version: [django4.0, django3.2, django3.1, django3.0]
+ drf-version: [drf3.14, drf3.13, drf3.12, drf3.11]
name: ${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.django-version }}-${{ matrix.drf-version }}
steps:
- name: "Set job environments"
@@ -66,7 +44,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
- python -m pip install --upgrade tox tox-gh-actions testfixtures
+ python -m pip install --upgrade 'tox>=3,<4' tox-gh-actions testfixtures
- name: Tox tests
run: |
tox -e $TOXENV
@@ -89,10 +67,10 @@ jobs:
needs: run-tests
steps:
- uses: actions/checkout@master
- - name: Set up Python 3.7
+ - name: Set up Python 3.9
uses: actions/setup-python@v1
with:
- python-version: 3.7
+ python-version: 3.9
- name: Install pypa/build
run: >-
python -m
diff --git a/README.rst b/README.rst
index cbc7632..d3e7cab 100644
--- a/README.rst
+++ b/README.rst
@@ -32,14 +32,11 @@ Compatibility
- `Django `_:
- - 2.0.x
- - 2.1.x
- - 2.2.x
- 3.0.x
- 3.1.x
- 3.2.x
-
-**NOTE**: Python 3.6 does not have support for Django <= 1.x.
+ - 4.0.x
+ - 4.1.x
**NOTE**: The 1.4 release dropped support for Django 1.5.x & 1.6.x.
@@ -47,14 +44,16 @@ Compatibility
**NOTE**: The 2.1 release dropped support for Django 1.9.x.
-- `Pillow `_ >= 2.4.0
+**NOTE**: The 3.0 release dropped support for Django 2.x.
+
+- `Pillow `_ >= 6.2.0
- `Django REST Framework `_:
- - 3.9.x
- - 3.10.x
- 3.11.x
- 3.12.x
+ - 3.13.x
+ - 3.14.x
Documentation
=============
diff --git a/docs/index.rst b/docs/index.rst
index 4617243..1e5ddca 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -39,20 +39,20 @@ Compatibility
- `Django `_:
- - 2.0.x
- - 2.1.x
- - 2.2.x
- 3.0.x
- 3.1.x
- 3.2.x
+ - 4.0.x
+ - 4.1.x
- `Pillow `_ >=2.4.0
- `Django REST Framework `_:
- - 3.9.x
- - 3.10.x
+ - 3.11.x
- 3.12.x
+ - 3.13.x
+ - 3.14.x
Code
====
@@ -78,6 +78,12 @@ Table of Contents
Release Notes
=============
+3.0
+^^^
+- Removed support for Django < 3.x. Thanks, `@browniebroke `_!
+- Added support for Django 4.0 & 4.1. Thanks, `@browniebroke `_!
+- General code clean-up, improved Django REST Framework support and doc updates. Thanks, `@browniebroke `_!
+
2.2
^^^
- Added WEBP support for sizers & filters. Thanks, `@ahmedaljazzar `_!
diff --git a/docs/installation.rst b/docs/installation.rst
index d6a6b04..110d086 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -18,11 +18,11 @@ Python Compatibility
Django Compatibility
--------------------
-- 2.0.x
-- 2.2.x
- 3.0.x
- 3.1.x
- 3.2.x
+- 4.0.x
+- 4.1.x
Dependencies
------------
diff --git a/docs/overview.rst b/docs/overview.rst
index 8f9a681..9cc3f97 100644
--- a/docs/overview.rst
+++ b/docs/overview.rst
@@ -151,7 +151,7 @@ Flexible in development, light-weight in production
Fully Tested & Python 3 Ready
-----------------------------
-``django-versatileimagefield`` is a rock solid, `fully-tested `_ Django app that is compatible with Python 3.6 thru 3.9 and works with Django 2.0.x thru 3.2.x
+``django-versatileimagefield`` is a rock solid, `fully-tested `_ Django app that is compatible with Python 3.6 thru 3.9 and works with Django 3.0.x thru 4.1.x
Get Started
-----------
diff --git a/post_processor_runtests.py b/post_processor_runtests.py
index 1743b74..3591fc1 100644
--- a/post_processor_runtests.py
+++ b/post_processor_runtests.py
@@ -11,8 +11,7 @@
from django.test.utils import get_runner
# Run post-processor tests
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.post_processor.test_settings'
- if django.VERSION >= (1, 7):
- django.setup()
+ django.setup()
TestRunnerPostProcessor = get_runner(
settings,
'tests.post_processor.discover_tests.DiscoverPostProcessorRunner'
diff --git a/setup.py b/setup.py
index 591eab8..1618cbb 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
name='django-versatileimagefield',
packages=find_packages(),
version='2.2',
- author=u'Jonathan Ellenberger',
+ author='Jonathan Ellenberger',
author_email='jonathan_ellenberger@wgbh.org',
url='http://github.com/respondcreate/django-versatileimagefield/',
license='MIT License, see LICENSE',
@@ -15,7 +15,11 @@
"creating new images from the one assigned to the field.",
long_description=open('README.rst').read(),
zip_safe=False,
- install_requires=['Pillow>=2.4.0', 'python-magic>=0.4.15,<1.0.0'],
+ install_requires=[
+ 'Pillow>=2.4.0',
+ 'python-magic>=0.4.15,<1.0.0',
+ 'Django>=3.0',
+ ],
include_package_data=True,
keywords=[
'django',
@@ -24,20 +28,17 @@
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Framework :: Django',
- 'Framework :: Django :: 2.0',
- 'Framework :: Django :: 2.1',
- 'Framework :: Django :: 2.2',
'Framework :: Django :: 3.0',
'Framework :: Django :: 3.1',
'Framework :: Django :: 3.2',
+ 'Framework :: Django :: 4.0',
+ 'Framework :: Django :: 4.1',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
diff --git a/tests/settings_base.py b/tests/settings_base.py
index f193fb5..a03976a 100644
--- a/tests/settings_base.py
+++ b/tests/settings_base.py
@@ -75,3 +75,5 @@
},
},
]
+
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
diff --git a/tests/tests.py b/tests/tests.py
index 3415ac7..9dcde45 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -421,7 +421,7 @@ def test_widget_javascript(self):
response = self.client.get(self.admin_url)
self.assertEqual(response.status_code, 200)
# Test that javascript loads correctly
- if DJANGO_VERSION[0] >= 3 and DJANGO_VERSION[1] >= 1:
+ if DJANGO_VERSION >= (3, 1):
expected_response = ''
else:
expected_response = ''
@@ -1081,28 +1081,6 @@ def test_corrupt_file(self):
instance.image.delete(save=False)
- @skipIf(django.VERSION >= (2, 2), "Not applicable for Django>=2.2")
- def test_webp_wrong_dimensions(self):
- """Test WebP image dimensions behavior on Django<2.2"""
- with self.assertRaisesMessage(RuntimeError, "could not create decoder object"):
- VersatileImageTestModel.objects.create(
- img_type='webp-no-dimensions',
- image="python-logo.webp",
- width=0,
- height=0
- )
-
- try:
- VersatileImageTestModel.objects.create(
- img_type='webp-with-dimensions',
- image="python-logo.webp",
- width=580,
- height=164
- )
- except RuntimeError as e:
- self.fail("ImageField raised RuntimeError unexpectedly! msg: %s" % e)
-
- @skipIf(django.VERSION < (2, 2), "Different behavior exists on Django<2.2")
def test_webp_dimensions_dimensions(self):
"""Test no failures on all WebP image dimensions"""
try:
diff --git a/tests/urls.py b/tests/urls.py
index aec6259..5e88d8c 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,19 +1,19 @@
from django.conf import settings
-from django.conf.urls import include, url
+from django.urls import include, path, re_path
from django.contrib import admin
admin.autodiscover()
urlpatterns = [
- url(r'^admin/', admin.site.urls),
+ path('admin/', admin.site.urls),
]
if settings.DEBUG:
urlpatterns = [
- url(
+ re_path(
r'^media/(?P.*)$',
'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}
),
- url(r'', include('django.contrib.staticfiles.urls')),
+ path('', include('django.contrib.staticfiles.urls')),
] + urlpatterns
diff --git a/tox.ini b/tox.ini
index 048261f..1a22f46 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,24 +3,20 @@ minversion = 3.23.0
requires:
pip >= 21.0.1
envlist =
- py{3.6,3.7}-django{20,21,22}-drf{307,308,309,310,311}
- py{3.8,3.9}-django{22}-drf{309,310,311,312}
- py{3.8,3.9}-django{30,31,32}-drf{311,312}
+ py{3.8,3.9}-django{30,31,32,40,41}-drf{311,312,313,314}
[gh-actions]
python =
- 3.6: py3.6
- 3.7: py3.7
3.8: py3.8
3.9: py3.9
[travis:env]
DJANGO =
- 2.0: django20
- 2.2: django22
3.0: django30
3.1: django31
3.2: django32
+ 4.0: django40
+ 4.1: django41
[testenv]
passenv = TRAVIS TRAVIS_* GITHUB_*
@@ -28,23 +24,17 @@ deps=
coverage
coveralls
testfixtures
- django20: Django>=2.0.13,<2.1.0
- django21: Django>=2.1.14,<2.2.0
- django22: Django>=2.2.19,<3.0.0
+ pytz
django30: Django>=3.0.13,<3.1.0
django31: Django>=3.1.7,<3.2.0
- django32: Django>=3.2.0rc1,<3.3.0
- drf304: djangorestframework>=3.4.7,<3.5.0
- drf305: djangorestframework>=3.5.4,<3.6.0
- drf306: djangorestframework>=3.6.4,<3.7.0
- drf307: djangorestframework>=3.7.7,<3.8.0
- drf308: djangorestframework>=3.8.2,<3.9.0
- drf309: djangorestframework>=3.9.4,<3.10.0
- drf310: djangorestframework>=3.10.3,<3.11.0
+ django32: Django>=3.2.0,<3.3.0
+ django40: Django>=4.0.0,<4.1.0
+ django41: Django>=4.1.0,<4.2.0
drf311: djangorestframework>=3.11.2,<3.12.0
drf312: djangorestframework>=3.12.4,<3.13.0
+ drf313: djangorestframework>=3.13,<3.14
+ drf314: djangorestframework>=3.14,<3.15
flake8
- coveralls
sitepackages = False
recreate = False
commands =
diff --git a/versatileimagefield/files.py b/versatileimagefield/files.py
index 019d322..d8bb4be 100644
--- a/versatileimagefield/files.py
+++ b/versatileimagefield/files.py
@@ -13,7 +13,7 @@ class VersatileImageFieldFile(VersatileImageMixIn, ImageFieldFile):
def __setstate__(self, state):
self.__dict__.update(state)
- if DJANGO_VERSION[0] >= 3 and DJANGO_VERSION[1] > 0:
+ if DJANGO_VERSION >= (3, 1):
self.storage = self.field.storage
self._create_on_demand = state.get('_create_on_demand')
self._ppoi_value = state.get('_ppoi_value')
diff --git a/versatileimagefield/widgets.py b/versatileimagefield/widgets.py
index 766a4b7..189681a 100644
--- a/versatileimagefield/widgets.py
+++ b/versatileimagefield/widgets.py
@@ -1,6 +1,4 @@
-import django
from django.forms.widgets import ClearableFileInput, HiddenInput, MultiWidget, Select
-from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
CENTERPOINT_CHOICES = (
@@ -18,7 +16,6 @@
class ClearableFileInputWithImagePreview(ClearableFileInput):
- has_template_widget_rendering = django.VERSION >= (1, 11)
template_name = 'versatileimagefield/forms/widgets/versatile_image.html'
def get_hidden_field_id(self, name):
@@ -36,20 +33,6 @@ def get_ppoi_id(self, name):
def get_point_stage_id(self, name):
return name + '_point-stage'
- def render(self, name, value, attrs=None, renderer=None):
- """
- Render the widget as an HTML string.
-
- Overridden here to support Django < 1.11.
- """
- if self.has_template_widget_rendering:
- return super(ClearableFileInputWithImagePreview, self).render(
- name, value, attrs=attrs, renderer=renderer
- )
- else: # pragma: no cover
- context = self.get_context(name, value, attrs)
- return render_to_string(self.template_name, context)
-
def get_sized_url(self, value):
"""Do not fail completely on invalid images"""
try:
@@ -63,11 +46,7 @@ def get_sized_url(self, value):
def get_context(self, name, value, attrs):
"""Get the context to render this widget with."""
- # Initialize widget context.
- context = {}
-
- if self.has_template_widget_rendering:
- context = super(ClearableFileInputWithImagePreview, self).get_context(name, value, attrs)
+ context = super(ClearableFileInputWithImagePreview, self).get_context(name, value, attrs)
# It seems Django 1.11's ClearableFileInput doesn't add everything to the 'widget' key, so we can't use it
# in MultiWidget. Add it manually here.