Add tests for named groups

This commit is contained in:
Drew Hubl 2016-09-23 05:55:08 -06:00
parent 203411c3cf
commit 95a47c7d22
5 changed files with 85 additions and 57 deletions

View file

@ -7,45 +7,45 @@ python:
- "3.4" - "3.4"
- "3.5" - "3.5"
env: env:
- DJANGO=1.4 - DJANGO=1.4.22
- DJANGO=1.5 - DJANGO=1.5.12
- DJANGO=1.6 - DJANGO=1.6.11
- DJANGO=1.7 - DJANGO=1.7.11
- DJANGO=1.8 - DJANGO=1.8.14
- DJANGO=1.9 - DJANGO=1.9.9
- DJANGO=1.10 - DJANGO=1.10.1
matrix: matrix:
exclude: exclude:
- python: "2.6" - python: "2.6"
env: DJANGO=1.7 env: DJANGO=1.7.11
- python: "2.6" - python: "2.6"
env: DJANGO=1.8 env: DJANGO=1.8.14
- python: "2.6" - python: "2.6"
env: DJANGO=1.9 env: DJANGO=1.9.9
- python: "2.6" - python: "2.6"
env: DJANGO=1.10 env: DJANGO=1.10.1
- python: "3.3" - python: "3.3"
env: DJANGO=1.4 env: DJANGO=1.4.22
- python: "3.4" - python: "3.4"
env: DJANGO=1.4 env: DJANGO=1.4.22
- python: "3.5" - python: "3.5"
env: DJANGO=1.4 env: DJANGO=1.4.22
- python: "3.3" - python: "3.3"
env: DJANGO=1.5 env: DJANGO=1.5.12
- python: "3.4" - python: "3.4"
env: DJANGO=1.5 env: DJANGO=1.5.12
- python: "3.5" - python: "3.5"
env: DJANGO=1.5 env: DJANGO=1.5.12
- python: "3.4" - python: "3.4"
env: DJANGO=1.6 env: DJANGO=1.6.11
- python: "3.5" - python: "3.5"
env: DJANGO=1.6 env: DJANGO=1.6.11
- python: "3.5" - python: "3.5"
env: DJANGO=1.7 env: DJANGO=1.7.11
- python: "3.3" - python: "3.3"
env: DJANGO=1.9 env: DJANGO=1.9.9
- python: "3.3" - python: "3.3"
env: DJANGO=1.10 env: DJANGO=1.10.1
install: install:
- pip install -q Django==$DJANGO - pip install -q Django==$DJANGO

View file

@ -17,6 +17,10 @@ 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.6, 2.7, 3.3+
Supported Django versions: 1.4-1.0+
Installation Installation
============ ============
@ -75,11 +79,15 @@ Only you need it, if you want the translation of django-multiselectfield
Known Bugs and Limitations Known Bugs and Limitations
========================== ==========================
Only in Django 1.6 and 1.7, due to `Django bug #9619 <https://code.djangoproject.com/ticket/9619>`_, passing a MultiSelectField to ``values()`` or ``values_list()`` will return the database representation of the field (a string of comma-separated values). The workaround is to manually call ``.split(',')`` on the result. All tests pass on Django 1.4, 1.5, and 1.8+, so if you can, use a modern version of Django. However, if you must use Django 1.6 or 1.7 there are two known issues you will need to be aware of:
The Django bug was introduced in Django 1.6 and is fixed in Django 1.8 and onward, so ``values()`` and ``values_list()`` return a vanilla Python list of values for Django <= 1.5 and Django >= 1.8. 1. `Named groups <https://github.com/goinnn/django-multiselectfield/pull/30#issue-52149983>`_ do not render properly in Django 1.6. The workaround is to manually render the field in your form or use a custom widget. If your workaround is suitably generic, please submit a pull request with it.
See `issue #40 <https://github.com/goinnn/django-multiselectfield/issues/40>`_ for discussion about this bug. 2. Only in Django 1.6 and 1.7, due to `Django bug #9619 <https://code.djangoproject.com/ticket/9619>`_, passing a MultiSelectField to ``values()`` or ``values_list()`` will return the database representation of the field (a string of comma-separated values). The workaround is to manually call ``.split(',')`` on the result.
The Django bug was introduced in Django 1.6 and is fixed in Django 1.8 and onward, so ``values()`` and ``values_list()`` return a vanilla Python list of values for Django <= 1.5 and Django >= 1.8.
See `issue #40 <https://github.com/goinnn/django-multiselectfield/issues/40>`_ for discussion about this bug.
Development Development
@ -96,11 +104,10 @@ of its git repository:
Example project Example project
=============== ===============
In the source tree, you will find a directory called `example <https://github.com/goinnn/django-multiselectfield/tree/master/example/>`_. It contains There is a fully configured example project in the `example directory <https://github.com/goinnn/django-multiselectfield/tree/master/example/>`_. You can run it as usual:
a readily setup project that uses django-multiselectfield. You can run it as usual:
.. code-block:: bash .. code-block:: bash
python manage.py syncdb --noinput python manage.py migrate # or python manage.py syncdb --noinput
python manage.py loaddata app_data python manage.py loaddata app_data
python manage.py runserver python manage.py runserver

View file

@ -20,11 +20,11 @@ from django.utils.translation import gettext as _
from multiselectfield import MultiSelectField from multiselectfield import MultiSelectField
CATEGORY_CHOICES = ( CATEGORY_CHOICES = (
(1, 'Handbooks and manuals by discipline'), (1, _('Handbooks and manuals by discipline')),
(2, 'Business books'), (2, _('Business books')),
(3, 'Books of literary criticism'), (3, _('Books of literary criticism')),
(4, 'Books about literary theory'), (4, _('Books about literary theory')),
(5, 'Books about literature') (5, _('Books about literature')),
) )
TAGS_CHOICES = ( TAGS_CHOICES = (
@ -64,7 +64,9 @@ class Book(models.Model):
default=1) default=1)
tags = MultiSelectField(choices=TAGS_CHOICES, tags = MultiSelectField(choices=TAGS_CHOICES,
null=True, blank=True) null=True, blank=True)
published_in = MultiSelectField(_("Province or State"), max_length=2, choices=PROVINCES_AND_STATES) published_in = MultiSelectField(_("Province or State"),
choices=PROVINCES_AND_STATES,
max_choices=2)
def __str__(self): def __str__(self):
return self.title return self.title

View file

@ -23,7 +23,7 @@ from django.test import TestCase
from multiselectfield.utils import get_max_length from multiselectfield.utils import get_max_length
from .models import Book, PROVINCES, STATES from .models import Book, PROVINCES, STATES, PROVINCES_AND_STATES
if sys.version_info < (3,): if sys.version_info < (3,):
@ -43,6 +43,7 @@ else:
class MultiSelectTestCase(TestCase): class MultiSelectTestCase(TestCase):
fixtures = ['app_data.json'] fixtures = ['app_data.json']
maxDiff = 4000
def assertListEqual(self, left, right, msg=None): def assertListEqual(self, left, right, msg=None):
if sys.version_info >= (3, 2): if sys.version_info >= (3, 2):
@ -128,10 +129,28 @@ class MultiSelectTestCase(TestCase):
self.assertEqual(get_field(Book, 'categories').value_to_string(book), '1,3,5') self.assertEqual(get_field(Book, 'categories').value_to_string(book), '1,3,5')
def test_flatchoices(self): def test_flatchoices(self):
#raise Exception(Book._meta.get_field('published_in').flatchoices)
# raise Exception(Book.published_in.flatchoices)
self.assertEqual(get_field(Book, 'published_in').flatchoices, list(PROVINCES+STATES)) self.assertEqual(get_field(Book, 'published_in').flatchoices, list(PROVINCES+STATES))
def test_named_groups(self):
self.assertEqual(get_field(Book, 'published_in').choices, PROVINCES_AND_STATES)
def test_named_groups_form(self):
form_class = modelform_factory(Book, fields=('published_in',))
self.assertEqual(len(form_class.base_fields), 1)
form = form_class(initial={'published_in': ['BC', 'AK']})
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>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_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()
if VERSION < (1, 6) or VERSION >= (1, 7):
# 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', ''))
class MultiSelectUtilsTestCase(TestCase): class MultiSelectUtilsTestCase(TestCase):
def test_get_max_length_max_length_is_not_none(self): def test_get_max_length_max_length_is_not_none(self):

40
tox.ini
View file

@ -14,7 +14,7 @@ install_command =
[testenv:py26-dj14] [testenv:py26-dj14]
basepython = python2.6 basepython = python2.6
deps = deps =
django==1.4.10 django==1.4.22
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -22,7 +22,7 @@ deps =
[testenv:py26-dj15] [testenv:py26-dj15]
basepython = python2.6 basepython = python2.6
deps = deps =
django==1.5.5 django==1.5.12
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -30,7 +30,7 @@ deps =
[testenv:py26-dj16] [testenv:py26-dj16]
basepython = python2.6 basepython = python2.6
deps = deps =
django==1.6 django==1.6.11
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -39,7 +39,7 @@ deps =
[testenv:py27-dj14] [testenv:py27-dj14]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.4.10 django==1.4.22
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -47,7 +47,7 @@ deps =
[testenv:py27-dj15] [testenv:py27-dj15]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.5.5 django==1.5.12
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -55,7 +55,7 @@ deps =
[testenv:py27-dj16] [testenv:py27-dj16]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.6 django==1.6.11
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -63,7 +63,7 @@ deps =
[testenv:py27-dj17] [testenv:py27-dj17]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.7 django==1.7.11
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -71,7 +71,7 @@ deps =
[testenv:py27-dj18] [testenv:py27-dj18]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.8 django==1.8.14
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -79,7 +79,7 @@ deps =
[testenv:py27-dj19] [testenv:py27-dj19]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.9 django==1.9.9
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -87,7 +87,7 @@ deps =
[testenv:py27-dj110] [testenv:py27-dj110]
basepython = python2.7 basepython = python2.7
deps = deps =
django==1.10 django==1.10.1
pillow==1.7.8 pillow==1.7.8
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -96,7 +96,7 @@ deps =
[testenv:py33-dj16] [testenv:py33-dj16]
basepython = python3.3 basepython = python3.3
deps = deps =
django==1.6 django==1.6.11
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -104,7 +104,7 @@ deps =
[testenv:py33-dj17] [testenv:py33-dj17]
basepython = python3.3 basepython = python3.3
deps = deps =
django==1.7 django==1.7.11
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -112,7 +112,7 @@ deps =
[testenv:py33-dj18] [testenv:py33-dj18]
basepython = python3.3 basepython = python3.3
deps = deps =
django==1.8 django==1.8.14
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -121,7 +121,7 @@ deps =
[testenv:py34-dj17] [testenv:py34-dj17]
basepython = python3.4 basepython = python3.4
deps = deps =
django==1.7 django==1.7.11
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -129,7 +129,7 @@ deps =
[testenv:py34-dj18] [testenv:py34-dj18]
basepython = python3.4 basepython = python3.4
deps = deps =
django==1.8 django==1.8.14
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -137,7 +137,7 @@ deps =
[testenv:py34-dj19] [testenv:py34-dj19]
basepython = python3.4 basepython = python3.4
deps = deps =
django==1.9 django==1.9.9
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -145,7 +145,7 @@ deps =
[testenv:py34-dj110] [testenv:py34-dj110]
basepython = python3.4 basepython = python3.4
deps = deps =
django==1.10 django==1.10.1
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -154,7 +154,7 @@ deps =
[testenv:py35-dj18] [testenv:py35-dj18]
basepython = python3.5 basepython = python3.5
deps = deps =
django==1.8 django==1.8.14
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -162,7 +162,7 @@ deps =
[testenv:py35-dj19] [testenv:py35-dj19]
basepython = python3.5 basepython = python3.5
deps = deps =
django==1.9 django==1.9.9
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3
@ -170,7 +170,7 @@ deps =
[testenv:py35-dj110] [testenv:py35-dj110]
basepython = python3.5 basepython = python3.5
deps = deps =
django==1.10 django==1.10.1
pillow==2.1.0 pillow==2.1.0
PyYAML==3.10 PyYAML==3.10
coveralls==0.3 coveralls==0.3