From c4579138dda2833cbce26afbf57da5353aa45690 Mon Sep 17 00:00:00 2001 From: Serj S Date: Fri, 1 Nov 2019 09:03:57 +0300 Subject: [PATCH] fix issue "TypeError: 'int' object is not iterable" during update (pre_save), add tests (#100) --- example/app/fixtures/app_data.json | 3 ++- example/app/migrations/0001_initial.py | 5 ++--- example/app/models.py | 8 ++++++++ example/app/test_msf.py | 24 ++++++++++++++++++++++-- multiselectfield/db/fields.py | 9 +++++++-- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/example/app/fixtures/app_data.json b/example/app/fixtures/app_data.json index 9ae79ff..b61a466 100644 --- a/example/app/fixtures/app_data.json +++ b/example/app/fixtures/app_data.json @@ -6,7 +6,8 @@ "title": "My book 1", "tags": "sex,work,happy", "categories": "1,3,5", - "published_in": "BC,AL,AK" + "published_in": "BC,AL,AK", + "chapters": "1" } }, { diff --git a/example/app/migrations/0001_initial.py b/example/app/migrations/0001_initial.py index 164054b..1122bc3 100644 --- a/example/app/migrations/0001_initial.py +++ b/example/app/migrations/0001_initial.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-09-22 20:34 -from __future__ import unicode_literals +# Generated by Django 2.2.6 on 2019-10-31 08:31 from django.db import migrations, models import multiselectfield.db.fields @@ -22,6 +20,7 @@ class Migration(migrations.Migration): ('categories', multiselectfield.db.fields.MultiSelectField(choices=[(1, 'Handbooks and manuals by discipline'), (2, 'Business books'), (3, 'Books of literary criticism'), (4, 'Books about literary theory'), (5, 'Books about literature')], default=1, max_length=9)), ('tags', multiselectfield.db.fields.MultiSelectField(blank=True, choices=[('sex', 'Sex'), ('work', 'Work'), ('happy', 'Happy'), ('food', 'Food'), ('field', 'Field'), ('boring', 'Boring'), ('interesting', 'Interesting'), ('huge', 'Huge'), ('nice', 'Nice')], max_length=54, null=True)), ('published_in', multiselectfield.db.fields.MultiSelectField(choices=[('Canada - Provinces', (('AB', 'Alberta'), ('BC', 'British Columbia'))), ('USA - States', (('AK', 'Alaska'), ('AL', 'Alabama'), ('AZ', 'Arizona')))], max_length=2, verbose_name='Province or State')), + ('chapters', multiselectfield.db.fields.MultiSelectField(choices=[(1, 'Chapter I'), (2, 'Chapter II')], default=1, max_length=3)), ], ), ] diff --git a/example/app/models.py b/example/app/models.py index eb2819d..0f8be73 100644 --- a/example/app/models.py +++ b/example/app/models.py @@ -27,6 +27,13 @@ CATEGORY_CHOICES = ( (5, _('Books about literature')), ) +ONE = 1 +TWO = 2 +CHAPTER_CHOICES = ( + (ONE, 'Chapter I'), + (TWO, 'Chapter II') +) + TAGS_CHOICES = ( ('sex', _('Sex')), # noqa: E241 ('work', _('Work')), # noqa: E241 @@ -67,6 +74,7 @@ class Book(models.Model): published_in = MultiSelectField(_("Province or State"), choices=PROVINCES_AND_STATES, max_choices=2) + chapters = MultiSelectField(choices=CHAPTER_CHOICES, default=ONE) def __str__(self): return self.title diff --git a/example/app/test_msf.py b/example/app/test_msf.py index ca121e7..4f4da13 100644 --- a/example/app/test_msf.py +++ b/example/app/test_msf.py @@ -23,8 +23,7 @@ from django.test import TestCase from multiselectfield.utils import get_max_length -from .models import Book, PROVINCES, STATES, PROVINCES_AND_STATES - +from .models import Book, PROVINCES, STATES, PROVINCES_AND_STATES, ONE, TWO if sys.version_info < (3,): u = unicode # noqa: F821 @@ -92,6 +91,27 @@ class MultiSelectTestCase(TestCase): if form.is_valid(): form.save() + def test_empty_update(self): + book = Book.objects.get(id=1) + self.assertEqual(book.get_chapters_list(), ["Chapter I"]) + book.chapters = {} + book.save(update_fields=['chapters']) + self.assertTrue(len(book.chapters) == 0) + + def test_single_update(self): + book = Book.objects.get(id=1) + self.assertEqual(book.get_chapters_list(), ["Chapter I"]) + book.chapters = {ONE} + book.save(update_fields=['chapters']) + self.assertEqual(book.get_chapters_list(), ["Chapter I"]) + + def test_multiple_update(self): + book = Book.objects.get(id=1) + self.assertEqual(book.get_chapters_list(), ["Chapter I"]) + book.chapters = {ONE, TWO} + book.save(update_fields=['chapters']) + self.assertEqual(book.get_chapters_list(), ["Chapter I", "Chapter II"]) + def test_object(self): book = Book.objects.get(id=1) self.assertEqual(book.get_tags_display(), 'Sex, Work, Happy') diff --git a/multiselectfield/db/fields.py b/multiselectfield/db/fields.py index cb5e68f..f0eb216 100644 --- a/multiselectfield/db/fields.py +++ b/multiselectfield/db/fields.py @@ -138,7 +138,7 @@ class MultiSelectField(models.CharField): return MultiSelectFormField(**defaults) def get_prep_value(self, value): - return '' if value is None else ",".join(value) + return '' if value is None else ",".join(map(str, value)) def get_db_prep_value(self, value, connection, prepared=False): if not prepared and not isinstance(value, string_type): @@ -149,7 +149,12 @@ class MultiSelectField(models.CharField): choices = dict(self.flatchoices) if value: - return value if isinstance(value, list) else MSFList(choices, value.split(',')) + if isinstance(value, list): + return value + elif isinstance(value, string_type): + return MSFList(choices, value.split(',')) + elif isinstance(value, (set, dict)): + return MSFList(choices, list(value)) return MSFList(choices, []) if VERSION < (2, ):