Adding back compatibility

This commit is contained in:
Tomas 2019-09-24 10:44:30 +02:00
parent 72177cc624
commit b2aad8da31
9 changed files with 373 additions and 40 deletions

View file

@ -1,27 +1,92 @@
language: python language: python
python: python:
- "2.6"
- "2.7" - "2.7"
- "3.3"
- "3.4" - "3.4"
- "3.5" - "3.5"
- "3.6" - "3.6"
env: env:
- DJANGO_VERSION='Django>=1.4,<1.5'
- DJANGO_VERSION='Django>=1.5,<1.6'
- DJANGO_VERSION='Django>=1.6,<1.7'
- DJANGO_VERSION='Django>=1.7,<1.8'
- DJANGO_VERSION='Django>=1.8,<1.9'
- DJANGO_VERSION='Django>=1.9,<1.10'
- DJANGO_VERSION='Django>=1.10,<1.11'
- DJANGO_VERSION='Django>=1.11,<2.0' - DJANGO_VERSION='Django>=1.11,<2.0'
- DJANGO_VERSION='Django>=2.0,<2.1' - DJANGO_VERSION='Django>=2.0,<2.1'
- DJANGO_VERSION='Django>=2.1,<2.2' - DJANGO_VERSION='Django>=2.1,<2.2'
- DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz' - DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'
matrix: matrix:
exclude: exclude:
- python: "2.6"
env: DJANGO_VERSION='Django>=1.7,<1.8'
- python: "2.6"
env: DJANGO_VERSION='Django>=1.8,<1.9'
- python: "2.6"
env: DJANGO_VERSION='Django>=1.9,<1.10'
- python: "2.6"
env: DJANGO_VERSION='Django>=1.10,<1.11'
- python: "2.6"
env: DJANGO_VERSION='Django>=1.11,<2.0'
- python: "2.6"
env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'
- python: "2.7" - python: "2.7"
env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'
- python: "3.3"
env: DJANGO_VERSION='Django>=1.4,<1.5'
- python: "3.3"
env: DJANGO_VERSION='Django>=1.5,<1.6'
- python: "3.3"
env: DJANGO_VERSION='Django>=1.9,<1.10'
- python: "3.3"
env: DJANGO_VERSION='Django>=1.10,<1.11'
- python: "3.3"
env: DJANGO_VERSION='Django>=1.11,<2.0'
- python: "3.3"
env: DJANGO_VERSION='Django>=2.0,<2.1' env: DJANGO_VERSION='Django>=2.0,<2.1'
- python: "2.7" - python: "2.7"
env: DJANGO_VERSION='Django>=2.1,<2.2' env: DJANGO_VERSION='Django>=2.1,<2.2'
- python: "2.7" - python: "2.7"
env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz' env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'
- python: "3.4"
env: DJANGO_VERSION='Django>=1.4,<1.5'
- python: "3.4"
env: DJANGO_VERSION='Django>=1.5,<1.6'
- python: "3.4"
env: DJANGO_VERSION='Django>=1.6,<1.7'
- python: "3.4" - python: "3.4"
env: DJANGO_VERSION='Django>=2.1,<2.2' env: DJANGO_VERSION='Django>=2.1,<2.2'
- python: "2.7" - python: "2.7"
env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz' env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'
- python: "3.5"
env: DJANGO_VERSION='Django>=1.4,<1.5'
- python: "3.5"
env: DJANGO_VERSION='Django>=1.5,<1.6'
- python: "3.5"
env: DJANGO_VERSION='Django>=1.6,<1.7'
- python: "3.5"
env: DJANGO_VERSION='Django>=1.7,<1.8'
- python: "3.5"
env: DJANGO_VERSION='Django>=2.1,<=2.2'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.4,<1.5'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.5,<1.6'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.6,<1.7'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.7,<1.8'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.8,<1.9'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.9,<1.10'
- python: "3.6"
env: DJANGO_VERSION='Django>=1.10,<1.11'
- python: "3.6"
env: DJANGO_VERSION='Django>=2.1,<=2.2'
allow_failures: allow_failures:
- env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz' - env: DJANGO_VERSION='https://github.com/django/django/archive/master.tar.gz'

View file

@ -14,9 +14,9 @@ A new model field and form field. With this you can get a multiple select from a
This egg is inspired by this `snippet <http://djangosnippets.org/snippets/1200/>`_. This egg is inspired by this `snippet <http://djangosnippets.org/snippets/1200/>`_.
Supported Python versions: 2.7, 3.4+ Supported Python versions: 2.6, 2.7, 3.3+
Supported Django versions: 1.11-2.0+ Supported Django versions: 1.4-2.0+
Installation Installation
============ ============
@ -35,25 +35,25 @@ Configure your models.py
.. code-block:: python .. code-block:: python
from multiselectfield import MultiSelectField from multiselectfield import MultiSelectField
# ... # ...
MY_CHOICES = (('item_key1', 'Item title 1.1'), MY_CHOICES = (('item_key1', 'Item title 1.1'),
('item_key2', 'Item title 1.2'), ('item_key2', 'Item title 1.2'),
('item_key3', 'Item title 1.3'), ('item_key3', 'Item title 1.3'),
('item_key4', 'Item title 1.4'), ('item_key4', 'Item title 1.4'),
('item_key5', 'Item title 1.5')) ('item_key5', 'Item title 1.5'))
MY_CHOICES2 = ((1, 'Item title 2.1'), MY_CHOICES2 = ((1, 'Item title 2.1'),
(2, 'Item title 2.2'), (2, 'Item title 2.2'),
(3, 'Item title 2.3'), (3, 'Item title 2.3'),
(4, 'Item title 2.4'), (4, 'Item title 2.4'),
(5, 'Item title 2.5')) (5, 'Item title 2.5'))
class MyModel(models.Model): class MyModel(models.Model):
# ..... # .....
my_field = MultiSelectField(choices=MY_CHOICES) my_field = MultiSelectField(choices=MY_CHOICES)
my_field2 = MultiSelectField(choices=MY_CHOICES2, my_field2 = MultiSelectField(choices=MY_CHOICES2,
max_choices=3, max_choices=3,
@ -103,7 +103,7 @@ Django REST Framework comes with a ``MultipleChoiceField`` that works perfectly
.. code-block:: python .. code-block:: python
from rest_framework import fields, serializers from rest_framework import fields, serializers
from myapp.models import MY_CHOICES, MY_CHOICES2 from myapp.models import MY_CHOICES, MY_CHOICES2
class MyModelSerializer(serializers.HyperlinkedModelSerializer): class MyModelSerializer(serializers.HyperlinkedModelSerializer):

View file

@ -32,8 +32,12 @@ else:
u = str u = str
def get_field(model, name): if VERSION < (1, 9):
return model._meta.get_field(name) def get_field(model, name):
return model._meta.get_field_by_name(name)[0]
else:
def get_field(model, name):
return model._meta.get_field(name)
class MultiSelectTestCase(TestCase): class MultiSelectTestCase(TestCase):
@ -73,8 +77,12 @@ class MultiSelectTestCase(TestCase):
# call Field.from_db_field, it simply returns a Python representation # call Field.from_db_field, it simply returns a Python representation
# of the data in the database (which in our case is a string of # of the data in the database (which in our case is a string of
# comma-separated values). The bug was fixed in Django 1.8+. # comma-separated values). The bug was fixed in Django 1.8+.
self.assertListEqual(tag_list_list, [['sex', 'work', 'happy']]) if VERSION >= (1, 6) and VERSION < (1, 8):
self.assertListEqual(categories_list_list, [['1', '3', '5']]) self.assertStringEqual(tag_list_list, [u('sex,work,happy')])
self.assertStringEqual(categories_list_list, [u('1,3,5')])
else:
self.assertListEqual(tag_list_list, [['sex', 'work', 'happy']])
self.assertListEqual(categories_list_list, [['1', '3', '5']])
def test_form(self): def test_form(self):
form_class = modelform_factory(Book, fields=('title', 'tags', 'categories')) form_class = modelform_factory(Book, fields=('title', 'tags', 'categories'))
@ -131,17 +139,28 @@ class MultiSelectTestCase(TestCase):
self.assertEqual(len(form_class.base_fields), 1) self.assertEqual(len(form_class.base_fields), 1)
form = form_class(initial={'published_in': ['BC', 'AK']}) form = form_class(initial={'published_in': ['BC', 'AK']})
expected_html = u("""<p><label>Province or State:</label> <ul id="id_published_in"><li>Canada - Provinces<ul id="id_published_in_0"><li><label for="id_published_in_0_0"><input id="id_published_in_0_0" name="published_in" type="checkbox" value="AB" /> Alberta</label></li>\n""" expected_html = u("""<p><label for="id_published_in_0">Province or State:</label> <ul id="id_published_in"><li>Canada - Provinces<ul id="id_published_in_0"><li><label for="id_published_in_0_0"><input id="id_published_in_0_0" name="published_in" type="checkbox" value="AB" /> Alberta</label></li>\n"""
"""<li><label for="id_published_in_0_1"><input checked="checked" id="id_published_in_0_1" name="published_in" type="checkbox" value="BC" /> British Columbia</label></li></ul></li>\n""" """<li><label for="id_published_in_0_1"><input checked="checked" id="id_published_in_0_1" name="published_in" type="checkbox" value="BC" /> British Columbia</label></li></ul></li>\n"""
"""<li>USA - States<ul id="id_published_in_1"><li><label for="id_published_in_1_0"><input checked="checked" id="id_published_in_1_0" name="published_in" type="checkbox" value="AK" /> Alaska</label></li>\n""" """<li>USA - States<ul id="id_published_in_1"><li><label for="id_published_in_1_0"><input checked="checked" id="id_published_in_1_0" name="published_in" type="checkbox" value="AK" /> Alaska</label></li>\n"""
"""<li><label for="id_published_in_1_1"><input id="id_published_in_1_1" name="published_in" type="checkbox" value="AL" /> Alabama</label></li>\n""" """<li><label for="id_published_in_1_1"><input id="id_published_in_1_1" name="published_in" type="checkbox" value="AL" /> Alabama</label></li>\n"""
"""<li><label for="id_published_in_1_2"><input id="id_published_in_1_2" name="published_in" type="checkbox" value="AZ" /> Arizona</label></li></ul></li></ul></p>""") """<li><label for="id_published_in_1_2"><input id="id_published_in_1_2" name="published_in" type="checkbox" value="AZ" /> Arizona</label></li></ul></li></ul></p>""")
actual_html = form.as_p() actual_html = form.as_p()
if (1, 11) <= VERSION < (2, 0):
# Django 1.11+ does not assign 'for' attributes on labels if they
# are group labels
expected_html = expected_html.replace('label for="id_published_in_0"', 'label')
if VERSION < (1, 6):
# Django 1.6 renders the Python repr() for each group (eg: tuples
# with HTML entities), so we skip the test for that version
self.assertEqual(expected_html.replace('\n', ''), actual_html.replace('\n', ''))
if VERSION >= (2, 0): if VERSION >= (2, 0):
expected_html = expected_html.replace('input checked="checked"', 'input checked') expected_html = expected_html.replace('input checked="checked"', 'input checked')
if VERSION >= (1, 7):
self.assertHTMLEqual(expected_html, actual_html)
self.assertHTMLEqual(expected_html, actual_html) self.assertHTMLEqual(expected_html, actual_html)

View file

@ -14,12 +14,15 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>. # along with this software. If not, see <http://www.gnu.org/licenses/>.
from django import VERSION
from django.conf import settings from django.conf import settings
from django.contrib.auth import login from django.contrib.auth import login
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.urls import reverse if VERSION >= (2, 0):
from django.urls import reverse
else:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect

View file

@ -14,11 +14,26 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with this software. If not, see <http://www.gnu.org/licenses/>. # along with this software. If not, see <http://www.gnu.org/licenses/>.
from django import VERSION
from django.conf import settings from django.conf import settings
try: try:
from django.conf.urls import include, url from django.conf.urls import include, url
except ImportError: # Compatibility for Django > 1.8
from django.urls import include, url def patterns(prefix, *args):
if VERSION < (1, 9):
from django.conf.urls import patterns as django_patterns
return django_patterns(prefix, *args)
elif prefix != '':
raise NotImplementedError("You need to update your URLConf for "
"Django 1.10, or tweak it to remove the "
"prefix parameter")
else:
return list(args)
except ImportError: # Django < 1.4
if VERSION < (1, 4):
from django.conf.urls.defaults import include, patterns, url
else:
from django.urls import include, url
from django.contrib import admin from django.contrib import admin
from django.views.static import serve from django.views.static import serve
@ -29,18 +44,26 @@ js_info_dict = {
'packages': ('django.conf',), 'packages': ('django.conf',),
} }
urlpatterns = [ if VERSION < (1, 11):
url(r'^', include('app.urls')), urlpatterns = patterns(
url(r'^admin/', admin.site.urls), '',
] url(r'^', include('app.urls')),
url(r'^admin/', include(admin.site.urls)),
urlpatterns += [ )
url( urlpatterns += patterns(
r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], '',
serve, url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:]),
{ )
'document_root': settings.MEDIA_ROOT, else:
'show_indexes': True, urlpatterns = [
}, url(r'^', include('app.urls')),
), url(r'^admin/', admin.site.urls),
] url(
r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:],
serve,
{
'document_root': settings.MEDIA_ROOT,
'show_indexes': True,
},
),
]

View file

@ -19,6 +19,7 @@
import os import os
import sys import sys
import django
from django.conf import ENVIRONMENT_VARIABLE from django.conf import ENVIRONMENT_VARIABLE
from django.core import management from django.core import management
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
@ -29,6 +30,10 @@ if len(sys.argv) == 1:
else: else:
os.environ[ENVIRONMENT_VARIABLE] = sys.argv[1] os.environ[ENVIRONMENT_VARIABLE] = sys.argv[1]
application = get_wsgi_application() if django.VERSION[0] == 1 and django.VERSION[1] >= 7:
from django.core.wsgi import get_wsgi_application as get_wsgi_application_v1
application = get_wsgi_application_v1()
else:
application = get_wsgi_application()
management.call_command('test', 'app') management.call_command('test', 'app')

View file

@ -102,7 +102,10 @@ class MultiSelectField(models.CharField):
return choices_selected return choices_selected
def value_to_string(self, obj): def value_to_string(self, obj):
value = super(MultiSelectField, self).value_from_object(obj) try:
value = self._get_val_from_obj(obj)
except AttributeError:
value = super(MultiSelectField, self).value_from_object(obj)
return self.get_prep_value(value) return self.get_prep_value(value)
def validate(self, value, model_instance): def validate(self, value, model_instance):

View file

@ -41,8 +41,10 @@ setup(
'Framework :: Django', 'Framework :: Django',
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
@ -54,13 +56,13 @@ setup(
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
tests_require=[ tests_require=[
'django>=1.11', 'django>=1.4',
'tox', 'tox',
'coverage', 'coverage',
'flake8', 'flake8',
], ],
install_requires=[ install_requires=[
'django>=1.11', 'django>=1.4',
], ],
zip_safe=False, zip_safe=False,
) )

219
tox.ini
View file

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py{27,34,35,36}-dj111,py{34,35,36,37}-dj20,py{35,36,37}-dj21 envlist = py{26,27,33,34,35,36}-dj{14,15,16,16,17,18,19,110,111},py{34,35,36,37}-dj{14,15,16,16,17,18,19,110,111,20},py{35,36,37}-dj{21,22},
[testenv] [testenv]
usedevelop = True usedevelop = True
@ -12,6 +12,141 @@ commands =
install_command = install_command =
pip install {opts} {packages} pip install {opts} {packages}
[testenv:py26-dj14]
basepython = python2.6
deps =
django==1.4.22
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj15]
basepython = python2.6
deps =
django==1.5.12
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj16]
basepython = python2.6
deps =
django==1.6.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj17]
basepython = python2.6
deps =
django==1.7.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj18]
basepython = python2.6
deps =
django==1.8.17
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj19]
basepython = python2.6
deps =
django==1.9.12
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj110]
basepython = python2.6
deps =
django==1.10.4
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py26-dj111]
basepython = python2.6
deps =
django==1.11.15
pillow==1.7.8
PyYAML==3.13
coveralls==0.3
flake8
[testenv:py27-dj14]
basepython = python2.7
deps =
django==1.4.22
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj15]
basepython = python2.7
deps =
django==1.5.12
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj16]
basepython = python2.7
deps =
django==1.6.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj17]
basepython = python2.7
deps =
django==1.7.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj18]
basepython = python2.7
deps =
django==1.8.17
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj19]
basepython = python2.7
deps =
django==1.9.12
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj110]
basepython = python2.7
deps =
django==1.10.4
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py27-dj111] [testenv:py27-dj111]
basepython = python2.7 basepython = python2.7
deps = deps =
@ -21,6 +156,59 @@ deps =
coveralls==0.3 coveralls==0.3
flake8 flake8
[testenv:py33-dj16]
basepython = python3.3
deps =
django==1.6.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py33-dj17]
basepython = python3.3
deps =
django==1.7.11
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py33-dj18]
basepython = python3.3
deps =
django==1.8.17
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py33-dj19]
basepython = python3.3
deps =
django==1.9.12
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py33-dj110]
basepython = python3.3
deps =
django==1.10.4
pillow==1.7.8
PyYAML==3.10
coveralls==0.3
flake8
[testenv:py33-dj111]
basepython = python3.3
deps =
django==1.11.15
pillow==1.7.8
PyYAML==3.13
coveralls==0.3
flake8
[testenv:py34-dj111] [testenv:py34-dj111]
basepython = python3.4 basepython = python3.4
@ -40,7 +228,6 @@ deps =
coveralls==0.3 coveralls==0.3
flake8 flake8
[testenv:py35-dj111] [testenv:py35-dj111]
basepython = python3.5 basepython = python3.5
deps = deps =
@ -68,6 +255,15 @@ deps =
coveralls==0.3 coveralls==0.3
flake8 flake8
[testenv:py35-dj22]
basepython = python3.5
deps =
django==2.2.1
pillow==2.1.0
PyYAML==3.13
coveralls==0.3
flake8
[testenv:py36-dj111] [testenv:py36-dj111]
basepython = python3.6 basepython = python3.6
deps = deps =
@ -95,6 +291,14 @@ deps =
coveralls==0.3 coveralls==0.3
flake8 flake8
[testenv:py36-dj22]
basepython = python3.6
deps =
django==2.2.1
pillow==2.1.0
PyYAML==3.13
coveralls==0.3
flake8
[testenv:py37-dj20] [testenv:py37-dj20]
basepython = python3.7 basepython = python3.7
@ -112,4 +316,13 @@ deps =
pillow==2.1.0 pillow==2.1.0
PyYAML==3.13 PyYAML==3.13
coveralls==0.3 coveralls==0.3
flake8 flake8
[testenv:py37-dj22]
basepython = python3.7
deps =
django==2.2.1
pillow==2.1.0
PyYAML==3.13
coveralls==0.3
flake8