Fix issue #33 - null VersionField breaks ORM

I've updated the `BaseSemVerField` method `get_prep_value` so that it
will return None when the field value is None, rather than the string
representation 'None'. Previously this would break the ORM, which would
save the string 'None' into the database, and then attempt to parse that
as a version number. This change means that the default empty value for
both VersionField and SpecField is None. Both derive from CharField,
which uses an empty string as its default empty value, however it seems
more logical in the case of these objects that no object is null, and
not an empty string.

Includes tests.
This commit is contained in:
Hugo Rodger-Brown 2015-11-24 22:32:32 +00:00
parent 2ed3d39c29
commit 0ef9524195
3 changed files with 47 additions and 1 deletions

View File

@ -20,6 +20,7 @@ The project has received contributions from (in alphabetical order):
* Raphaël Barrois <raphael.barrois+semver@polytechnique.org> (https://github.com/rbarrois)
* Michael Hrivnak <mhrivnak@hrivnak.org> (https://github.com/mhrivnak)
* Rick Eyre <rick.eyre@outlook.com> (https://github.com/rickeyre)
* Hugo Rodger-Brown <hugo@yunojuno.com> (https://github.com/yunojuno)
Contributor license agreement

View File

@ -18,7 +18,7 @@ class BaseSemVerField(models.CharField):
super(BaseSemVerField, self).__init__(*args, **kwargs)
def get_prep_value(self, obj):
return str(obj)
return None if obj is None else str(obj)
def get_db_prep_value(self, value, connection, prepared=False):
if not prepared:

View File

@ -30,6 +30,11 @@ if django_loaded and django.VERSION < (1, 7): # pragma: no cover
except ImportError:
pass
# the refresh_from_db method only came in with 1.8, so in order to make this
# work will all supported versions we have our own function
def refresh_from_db(obj):
return obj.__class__.objects.get(id=obj.id)
@unittest.skipIf(not django_loaded, "Django not installed")
class DjangoFieldTestCase(unittest.TestCase):
@ -48,6 +53,46 @@ class DjangoFieldTestCase(unittest.TestCase):
obj.full_clean()
def test_version_save(self):
"""Test saving object with a VersionField."""
# first test with a null value
obj = models.PartialVersionModel()
self.assertIsNone(obj.id)
self.assertIsNone(obj.optional)
obj.save()
# now retrieve from db
obj = refresh_from_db(obj)
self.assertIsNotNone(obj.id)
self.assertIsNone(obj.optional_spec)
# now set to something that is not null
spec = semantic_version.Spec('==0,!=0.2')
obj.optional_spec = spec
obj.save()
obj = refresh_from_db(obj)
self.assertEqual(obj.optional_spec, spec)
def test_spec_save(self):
"""Test saving object with a SpecField."""
# first test with a null value
obj = models.PartialVersionModel()
self.assertIsNone(obj.id)
self.assertIsNone(obj.optional_spec)
obj.save()
# now retrieve from db
obj.refresh_from_db()
self.assertIsNotNone(obj.id)
self.assertIsNone(obj.optional_spec)
# now set to something that is not null
spec = semantic_version.Spec('==0,!=0.2')
obj.optional_spec = spec
obj.save()
obj.refresh_from_db()
self.assertEqual(obj.optional_spec, spec)
def test_partial_spec(self):
obj = models.VersionModel(version='0.1.1', spec='==0,!=0.2')
self.assertEqual(semantic_version.Version('0.1.1'), obj.version)