Skip to content

Commit 39498a5

Browse files
authored
Merge pull request #61 from hzdg/issue-60
Restore cast-on-assign behavior on Django 1.8+
2 parents ba23793 + 13919f5 commit 39498a5

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

enumfields/fields.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,28 @@
1010
from .compat import import_string
1111
from .forms import EnumChoiceField
1212

13-
metaclass = models.SubfieldBase if django.VERSION < (1, 8) else type
1413

14+
class CastOnAssignDescriptor(object):
15+
"""
16+
A property descriptor which ensures that `field.to_python()` is called on _every_ assignment to the field.
1517
16-
class EnumFieldMixin(six.with_metaclass(metaclass)):
18+
This used to be provided by the `django.db.models.subclassing.Creator` class, which in turn
19+
was used by the deprecated-in-Django-1.10 `SubfieldBase` class, hence the reimplementation here.
20+
"""
21+
22+
def __init__(self, field):
23+
self.field = field
24+
25+
def __get__(self, obj, type=None):
26+
if obj is None:
27+
return self
28+
return obj.__dict__[self.field.name]
29+
30+
def __set__(self, obj, value):
31+
obj.__dict__[self.field.name] = self.field.to_python(value)
32+
33+
34+
class EnumFieldMixin(object):
1735
def __init__(self, enum, **options):
1836
if isinstance(enum, six.string_types):
1937
self.enum = import_string(enum)
@@ -25,6 +43,10 @@ def __init__(self, enum, **options):
2543

2644
super(EnumFieldMixin, self).__init__(**options)
2745

46+
def contribute_to_class(self, cls, name):
47+
super(EnumFieldMixin, self).contribute_to_class(cls, name)
48+
setattr(cls, name, CastOnAssignDescriptor(self))
49+
2850
def to_python(self, value):
2951
if value is None or value == '':
3052
return None

tests/test_issue_60.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import pytest
2+
3+
from .models import MyModel
4+
5+
try:
6+
from .enums import Color # Use the new location of Color enum
7+
except ImportError:
8+
Color = MyModel.Color # Attempt the 0.7.4 location of color enum
9+
10+
11+
@pytest.mark.django_db
12+
def test_fields_value_is_enum_when_unsaved():
13+
obj = MyModel(color='r')
14+
assert Color.RED == obj.color
15+
16+
17+
@pytest.mark.django_db
18+
def test_fields_value_is_enum_when_saved():
19+
obj = MyModel(color='r')
20+
obj.save()
21+
assert Color.RED == obj.color
22+
23+
24+
@pytest.mark.django_db
25+
def test_fields_value_is_enum_when_created():
26+
obj = MyModel.objects.create(color='r')
27+
assert Color.RED == obj.color
28+
29+
30+
@pytest.mark.django_db
31+
def test_fields_value_is_enum_when_retrieved():
32+
MyModel.objects.create(color='r')
33+
obj = MyModel.objects.all()[:1][0] # .first() not available on all Djangoes
34+
assert Color.RED == obj.color

0 commit comments

Comments
 (0)