diff --git a/.travis.yml b/.travis.yml index 0ce76de..27d1877 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ python: env: matrix: - DJANGO=111 + - DJANGO=20 - DJANGO=master - TOXENV=qa - TOXENV=docs diff --git a/CHANGELOG.md b/CHANGELOG.md index 07151c4..dd55148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Changelog Summary ### v6.0.0 +* Add Support for Django 2.0 * Drop Python 2 support * Drop Python 3.5 support * Drop Django 1.8 support diff --git a/django_select2/__init__.py b/django_select2/__init__.py index 62f1c49..d54a92b 100644 --- a/django_select2/__init__.py +++ b/django_select2/__init__.py @@ -7,3 +7,4 @@ The application includes Select2 driven Django Widgets and Form Fields. .. _Select2: http://ivaynberg.github.com/select2/ """ +default_app_config = 'django_select2.apps.Select2AppConfig' diff --git a/django_select2/apps.py b/django_select2/apps.py new file mode 100644 index 0000000..eef05e7 --- /dev/null +++ b/django_select2/apps.py @@ -0,0 +1,9 @@ +"""Django application configuration.""" +from django.apps import AppConfig + + +class Select2AppConfig(AppConfig): + """Django application configuration.""" + + name = 'django_select2' + verbose_name = 'Select2' diff --git a/django_select2/forms.py b/django_select2/forms.py index c82aa7c..432c529 100644 --- a/django_select2/forms.py +++ b/django_select2/forms.py @@ -54,8 +54,6 @@ from django.core import signing from django.db.models import Q from django.forms.models import ModelChoiceIterator from django.urls import reverse -from django.utils.encoding import force_text -from django.utils.six.moves.cPickle import PicklingError as cPicklingError from django.utils.translation import get_language from .cache import cache @@ -262,7 +260,7 @@ class HeavySelect2Mixin(object): 'widget': self, 'url': self.get_url(), }) - except (PicklingError, cPicklingError, AttributeError): + except (PicklingError, AttributeError): msg = "You need to overwrite \"set_to_cache\" or ensure that %s is serialisable." raise NotImplementedError(msg % self.__class__.__name__) @@ -426,7 +424,7 @@ class ModelSelect2Mixin(object): default = (None, [], 0) groups = [default] has_selected = False - selected_choices = {force_text(v) for v in value} + selected_choices = {str(v) for v in value} if not self.is_required and not self.allow_multiple_selected: default[1].append(self.create_option(name, '', '', False, 0)) if not isinstance(self.choices, ModelChoiceIterator): @@ -441,7 +439,7 @@ class ModelSelect2Mixin(object): ) for option_value, option_label in choices: selected = ( - force_text(option_value) in value and + str(option_value) in value and (has_selected is False or self.allow_multiple_selected) ) if selected is True and has_selected is False: @@ -461,7 +459,7 @@ class ModelSelect2Mixin(object): class MyWidget(ModelSelect2Widget): def label_from_instance(obj): - return force_text(obj.title).upper() + return str(obj.title).upper() Args: obj (django.db.models.Model): Instance of Django Model. @@ -470,7 +468,7 @@ class ModelSelect2Mixin(object): str: Option label. """ - return force_text(obj) + return str(obj) class ModelSelect2Widget(ModelSelect2Mixin, HeavySelect2Widget): @@ -537,10 +535,10 @@ class ModelSelect2TagWidget(ModelSelect2Mixin, HeavySelect2TagWidget): def value_from_datadict(self, data, files, name): values = super().value_from_datadict(self, data, files, name) qs = self.queryset.filter(**{'pk__in': list(values)}) - pks = set(force_text(getattr(o, pk)) for o in qs) + pks = set(str(getattr(o, pk)) for o in qs) cleaned_values = [] for val in value: - if force_text(val) not in pks: + if str(val) not in pks: val = queryset.create(title=val).pk cleaned_values.append(val) return cleaned_values diff --git a/django_select2/models.py b/django_select2/models.py deleted file mode 100644 index 2f9285d..0000000 --- a/django_select2/models.py +++ /dev/null @@ -1 +0,0 @@ -"""Django legacy file.""" diff --git a/tests/test_forms.py b/tests/test_forms.py index b3f29c3..539d1ce 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -103,38 +103,38 @@ class TestSelect2Mixin(object): def test_i18n(self): translation.activate('de') - assert Select2Widget().media._js == [ + assert tuple(Select2Widget().media._js) == ( '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/i18n/de.js', 'django_select2/django_select2.js' - ] + ) translation.activate('en') - assert Select2Widget().media._js == [ + assert tuple(Select2Widget().media._js) == ( '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/i18n/en.js', 'django_select2/django_select2.js' - ] + ) translation.activate('00') - assert Select2Widget().media._js == [ + assert tuple(Select2Widget().media._js) == ( '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js', 'django_select2/django_select2.js' - ] + ) translation.activate('sr-cyrl') - assert Select2Widget().media._js == [ + assert tuple(Select2Widget().media._js) == ( '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/i18n/sr-Cyrl.js', 'django_select2/django_select2.js' - ] + ) translation.activate('zh-cn') - assert Select2Widget().media._js == [ + assert tuple(Select2Widget().media._js) == ( '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/i18n/zh-CN.js', 'django_select2/django_select2.js' - ] + ) class TestSelect2MixinSettings(object): diff --git a/tests/testapp/.coverage b/tests/testapp/.coverage deleted file mode 100644 index fe8af93..0000000 --- a/tests/testapp/.coverage +++ /dev/null @@ -1 +0,0 @@ -!coverage.py: This is a private format, don't read it directly!{"lines":{}} \ No newline at end of file diff --git a/tests/testapp/models.py b/tests/testapp/models.py index 13a56c3..6687550 100644 --- a/tests/testapp/models.py +++ b/tests/testapp/models.py @@ -1,25 +1,27 @@ from django.db import models -from django.utils.encoding import python_2_unicode_compatible -@python_2_unicode_compatible class Genre(models.Model): title = models.CharField(max_length=50) + class Meta: + ordering = ('title',) + def __str__(self): return self.title -@python_2_unicode_compatible class Artist(models.Model): title = models.CharField(max_length=50) genres = models.ManyToManyField(Genre) + class Meta: + ordering = ('title',) + def __str__(self): return self.title -@python_2_unicode_compatible class Album(models.Model): title = models.CharField(max_length=255) artist = models.ForeignKey(Artist, on_delete=models.CASCADE) @@ -28,22 +30,29 @@ class Album(models.Model): related_name='primary_album_set') genres = models.ManyToManyField(Genre) + class Meta: + ordering = ('title',) + def __str__(self): return self.title -@python_2_unicode_compatible class Country(models.Model): name = models.CharField(max_length=255) + class Meta: + ordering = ('name',) + def __str__(self): return self.name -@python_2_unicode_compatible class City(models.Model): name = models.CharField(max_length=255) country = models.ForeignKey('Country', related_name="cities", on_delete=models.CASCADE) + class Meta: + ordering = ('name',) + def __str__(self): return self.name diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index c1b3a8c..4ab289f 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -20,7 +20,7 @@ INSTALLED_APPS = ( 'tests.testapp', ) -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', diff --git a/tox.ini b/tox.ini index b8f6f38..84e8cdd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{36}-dj{111,master},qa,docs +envlist = py{36}-dj{111,20,master},qa,docs [testenv] setenv= PYTHONPATH = {toxinidir} @@ -7,6 +7,7 @@ passenv=CI deps= -rrequirements-dev.txt dj111: https://github.com/django/django/archive/stable/1.11.x.tar.gz#egg=django + dj20: https://github.com/django/django/archive/stable/2.0.x.tar.gz#egg=django djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django commands= coverage run --source=django_select2 -m 'pytest' \ @@ -28,5 +29,5 @@ whitelist_externals=make changedir={toxinidir}/docs deps= -rrequirements-dev.txt - https://github.com/django/django/archive/stable/1.10.x.tar.gz#egg=django + https://github.com/django/django/archive/stable/1.11.x.tar.gz#egg=django commands=make spelling