mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Remove unsupported django version hacks.
This commit is contained in:
parent
82dfed6a84
commit
e6c7b567d1
9 changed files with 29 additions and 118 deletions
|
|
@ -81,9 +81,7 @@ class StatusField(models.CharField):
|
||||||
assert hasattr(sender, self.choices_name), \
|
assert hasattr(sender, self.choices_name), \
|
||||||
"To use StatusField, the model '%s' must have a %s choices class attribute." \
|
"To use StatusField, the model '%s' must have a %s choices class attribute." \
|
||||||
% (sender.__name__, self.choices_name)
|
% (sender.__name__, self.choices_name)
|
||||||
self._choices = getattr(sender, self.choices_name)
|
self.choices = getattr(sender, self.choices_name)
|
||||||
if django.VERSION >= (1, 9, 0):
|
|
||||||
self.choices = self._choices
|
|
||||||
if not self.has_default():
|
if not self.has_default():
|
||||||
self.default = tuple(getattr(sender, self.choices_name))[0][0] # set first as default
|
self.default = tuple(getattr(sender, self.choices_name))[0][0] # set first as default
|
||||||
|
|
||||||
|
|
@ -92,9 +90,7 @@ class StatusField(models.CharField):
|
||||||
# we don't set the real choices until class_prepared (so we can rely on
|
# we don't set the real choices until class_prepared (so we can rely on
|
||||||
# the STATUS class attr being available), but we need to set some dummy
|
# the STATUS class attr being available), but we need to set some dummy
|
||||||
# choices now so the super method will add the get_FOO_display method
|
# choices now so the super method will add the get_FOO_display method
|
||||||
self._choices = [(0, 'dummy')]
|
self.choices = [(0, 'dummy')]
|
||||||
if django.VERSION >= (1, 9, 0):
|
|
||||||
self.choices = self._choices
|
|
||||||
super(StatusField, self).contribute_to_class(cls, name)
|
super(StatusField, self).contribute_to_class(cls, name)
|
||||||
|
|
||||||
def deconstruct(self):
|
def deconstruct(self):
|
||||||
|
|
@ -133,11 +129,10 @@ class MonitorField(models.DateTimeField):
|
||||||
return getattr(instance, self.monitor)
|
return getattr(instance, self.monitor)
|
||||||
|
|
||||||
def _save_initial(self, sender, instance, **kwargs):
|
def _save_initial(self, sender, instance, **kwargs):
|
||||||
if django.VERSION >= (1, 10) and self.monitor in instance.get_deferred_fields():
|
if self.monitor in instance.get_deferred_fields():
|
||||||
# Fix related to issue #241 to avoid recursive error on double monitor fields
|
# Fix related to issue #241 to avoid recursive error on double monitor fields
|
||||||
return
|
return
|
||||||
setattr(instance, self.monitor_attname,
|
setattr(instance, self.monitor_attname, self.get_monitored_value(instance))
|
||||||
self.get_monitored_value(instance))
|
|
||||||
|
|
||||||
def pre_save(self, model_instance, add):
|
def pre_save(self, model_instance, add):
|
||||||
value = now()
|
value = now()
|
||||||
|
|
|
||||||
|
|
@ -114,35 +114,6 @@ class InheritanceQuerySetMixin(object):
|
||||||
qset._annotated = [a.default_alias for a in args] + list(kwargs.keys())
|
qset._annotated = [a.default_alias for a in args] + list(kwargs.keys())
|
||||||
return qset
|
return qset
|
||||||
|
|
||||||
def iterator(self):
|
|
||||||
# Maintained for Django 1.8 compatability
|
|
||||||
iter = super(InheritanceQuerySetMixin, self).iterator()
|
|
||||||
if getattr(self, 'subclasses', False):
|
|
||||||
extras = tuple(self.query.extra.keys())
|
|
||||||
# sort the subclass names longest first,
|
|
||||||
# so with 'a' and 'a__b' it goes as deep as possible
|
|
||||||
subclasses = sorted(self.subclasses, key=len, reverse=True)
|
|
||||||
for obj in iter:
|
|
||||||
sub_obj = None
|
|
||||||
for s in subclasses:
|
|
||||||
sub_obj = self._get_sub_obj_recurse(obj, s)
|
|
||||||
if sub_obj:
|
|
||||||
break
|
|
||||||
if not sub_obj:
|
|
||||||
sub_obj = obj
|
|
||||||
|
|
||||||
if getattr(self, '_annotated', False):
|
|
||||||
for k in self._annotated:
|
|
||||||
setattr(sub_obj, k, getattr(obj, k))
|
|
||||||
|
|
||||||
for k in extras:
|
|
||||||
setattr(sub_obj, k, getattr(obj, k))
|
|
||||||
|
|
||||||
yield sub_obj
|
|
||||||
else:
|
|
||||||
for obj in iter:
|
|
||||||
yield obj
|
|
||||||
|
|
||||||
def _get_subclasses_recurse(self, model, levels=None):
|
def _get_subclasses_recurse(self, model, levels=None):
|
||||||
"""
|
"""
|
||||||
Given a Model class, find all related objects, exploring children
|
Given a Model class, find all related objects, exploring children
|
||||||
|
|
@ -202,11 +173,6 @@ class InheritanceQuerySetMixin(object):
|
||||||
def _get_sub_obj_recurse(self, obj, s):
|
def _get_sub_obj_recurse(self, obj, s):
|
||||||
rel, _, s = s.partition(LOOKUP_SEP)
|
rel, _, s = s.partition(LOOKUP_SEP)
|
||||||
|
|
||||||
# Django 1.9: If a primitive type gets passed to this recursive function,
|
|
||||||
# return None as non-models are not part of inheritance.
|
|
||||||
if not isinstance(obj, models.Model):
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
node = getattr(obj, rel)
|
node = getattr(obj, rel)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,7 @@ from model_utils.managers import (
|
||||||
SoftDeletableManager,
|
SoftDeletableManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
if django.VERSION >= (1, 9, 0):
|
from django.utils.timezone import now
|
||||||
from django.db.models.functions import Now
|
|
||||||
now = Now()
|
|
||||||
else:
|
|
||||||
from django.utils.timezone import now
|
|
||||||
|
|
||||||
|
|
||||||
class TimeStampedModel(models.Model):
|
class TimeStampedModel(models.Model):
|
||||||
|
|
@ -75,9 +71,7 @@ def add_status_query_managers(sender, **kwargs):
|
||||||
if not issubclass(sender, StatusModel):
|
if not issubclass(sender, StatusModel):
|
||||||
return
|
return
|
||||||
|
|
||||||
if django.VERSION >= (1, 10):
|
default_manager = sender._meta.default_manager
|
||||||
# First, get current manager name...
|
|
||||||
default_manager = sender._meta.default_manager
|
|
||||||
|
|
||||||
for value, display in getattr(sender, 'STATUS', ()):
|
for value, display in getattr(sender, 'STATUS', ()):
|
||||||
if _field_exists(sender, value):
|
if _field_exists(sender, value):
|
||||||
|
|
@ -88,9 +82,7 @@ def add_status_query_managers(sender, **kwargs):
|
||||||
)
|
)
|
||||||
sender.add_to_class(value, QueryManager(status=value))
|
sender.add_to_class(value, QueryManager(status=value))
|
||||||
|
|
||||||
if django.VERSION >= (1, 10):
|
sender._meta.default_manager_name = default_manager.name
|
||||||
# ...then, put it back, as add_to_class is modifying the default manager!
|
|
||||||
sender._meta.default_manager_name = default_manager.name
|
|
||||||
|
|
||||||
|
|
||||||
def add_timeframed_query_manager(sender, **kwargs):
|
def add_timeframed_query_manager(sender, **kwargs):
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,6 @@ class FieldInstanceTracker(object):
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
self.field_map = field_map
|
self.field_map = field_map
|
||||||
if django.VERSION < (1, 10):
|
|
||||||
self.init_deferred_fields()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def deferred_fields(self):
|
def deferred_fields(self):
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,13 @@ def mutable_to_db(value):
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
if django.VERSION >= (1, 9, 0):
|
class MutableField(models.TextField):
|
||||||
class MutableField(models.TextField):
|
def to_python(self, value):
|
||||||
def to_python(self, value):
|
return mutable_from_db(value)
|
||||||
return mutable_from_db(value)
|
|
||||||
|
|
||||||
def from_db_value(self, value, expression, connection, context):
|
def from_db_value(self, value, expression, connection, context):
|
||||||
return mutable_from_db(value)
|
return mutable_from_db(value)
|
||||||
|
|
||||||
def get_db_prep_save(self, value, connection):
|
def get_db_prep_save(self, value, connection):
|
||||||
value = super(MutableField, self).get_db_prep_save(value, connection)
|
value = super(MutableField, self).get_db_prep_save(value, connection)
|
||||||
return mutable_to_db(value)
|
return mutable_to_db(value)
|
||||||
else:
|
|
||||||
class MutableField(with_metaclass(models.SubfieldBase, models.TextField)):
|
|
||||||
def to_python(self, value):
|
|
||||||
return mutable_from_db(value)
|
|
||||||
|
|
||||||
def get_db_prep_save(self, value, connection):
|
|
||||||
value = mutable_to_db(value)
|
|
||||||
return super(MutableField, self).get_db_prep_save(value, connection)
|
|
||||||
|
|
|
||||||
|
|
@ -185,35 +185,23 @@ class FieldTrackerTests(FieldTrackerTestCase, FieldTrackerCommonTests):
|
||||||
self.instance.number = 1
|
self.instance.number = 1
|
||||||
self.instance.save()
|
self.instance.save()
|
||||||
item = self.tracked_class.objects.only('name').first()
|
item = self.tracked_class.objects.only('name').first()
|
||||||
if django.VERSION >= (1, 10):
|
self.assertTrue(item.get_deferred_fields())
|
||||||
self.assertTrue(item.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertTrue(item._deferred_fields)
|
|
||||||
|
|
||||||
# has_changed() returns False for deferred fields, without un-deferring them.
|
# has_changed() returns False for deferred fields, without un-deferring them.
|
||||||
# Use an if because ModelTracked doesn't support has_changed() in this case.
|
# Use an if because ModelTracked doesn't support has_changed() in this case.
|
||||||
if self.tracked_class == Tracked:
|
if self.tracked_class == Tracked:
|
||||||
self.assertFalse(item.tracker.has_changed('number'))
|
self.assertFalse(item.tracker.has_changed('number'))
|
||||||
if django.VERSION >= (1, 10):
|
self.assertIsInstance(item.__class__.number, DescriptorWrapper)
|
||||||
self.assertIsInstance(item.__class__.number, DescriptorWrapper)
|
self.assertTrue('number' in item.get_deferred_fields())
|
||||||
self.assertTrue('number' in item.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertTrue('number' in item._deferred_fields)
|
|
||||||
|
|
||||||
# previous() un-defers field and returns value
|
# previous() un-defers field and returns value
|
||||||
self.assertEqual(item.tracker.previous('number'), 1)
|
self.assertEqual(item.tracker.previous('number'), 1)
|
||||||
if django.VERSION >= (1, 10):
|
self.assertNotIn('number', item.get_deferred_fields())
|
||||||
self.assertNotIn('number', item.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertNotIn('number', item._deferred_fields)
|
|
||||||
|
|
||||||
# examining a deferred field un-defers it
|
# examining a deferred field un-defers it
|
||||||
item = self.tracked_class.objects.only('name').first()
|
item = self.tracked_class.objects.only('name').first()
|
||||||
self.assertEqual(item.number, 1)
|
self.assertEqual(item.number, 1)
|
||||||
if django.VERSION >= (1, 10):
|
self.assertTrue('number' not in item.get_deferred_fields())
|
||||||
self.assertTrue('number' not in item.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertTrue('number' not in item._deferred_fields)
|
|
||||||
self.assertEqual(item.tracker.previous('number'), 1)
|
self.assertEqual(item.tracker.previous('number'), 1)
|
||||||
self.assertFalse(item.tracker.has_changed('number'))
|
self.assertFalse(item.tracker.has_changed('number'))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,15 +171,12 @@ class InheritanceManagerTests(TestCase):
|
||||||
queryset = InheritanceManagerTestChild1.objects.values('id').filter(pk=self.child1.pk)
|
queryset = InheritanceManagerTestChild1.objects.values('id').filter(pk=self.child1.pk)
|
||||||
self.assertEqual(list(queryset), [{'id': self.child1.pk}])
|
self.assertEqual(list(queryset), [{'id': self.child1.pk}])
|
||||||
|
|
||||||
@skipUnless(django.VERSION >= (1, 9, 0), "test only applies to Django 1.9+")
|
def test_values_list_on_select_subclasses(self):
|
||||||
def test_dj19_values_list_on_select_subclasses(self):
|
|
||||||
"""
|
"""
|
||||||
Using `select_subclasses` in conjunction with `values_list()` raised an
|
Using `select_subclasses` in conjunction with `values_list()` raised an
|
||||||
exception in `_get_sub_obj_recurse()` because the result of `values_list()`
|
exception in `_get_sub_obj_recurse()` because the result of `values_list()`
|
||||||
is either a `tuple` or primitive objects if `flat=True` is specified,
|
is either a `tuple` or primitive objects if `flat=True` is specified,
|
||||||
because no type checking was done prior to fetching child nodes.
|
because no type checking was done prior to fetching child nodes.
|
||||||
|
|
||||||
Django versions below 1.9 are not affected by this bug.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Querysets are cast to lists to force immediate evaluation.
|
# Querysets are cast to lists to force immediate evaluation.
|
||||||
|
|
@ -430,7 +427,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual([child3], list(results))
|
self.assertEqual([child3], list(results))
|
||||||
|
|
||||||
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
|
|
||||||
def test_limit_to_specific_grandchild_class(self):
|
def test_limit_to_specific_grandchild_class(self):
|
||||||
grandchild1 = InheritanceManagerTestGrandChild1.objects.get()
|
grandchild1 = InheritanceManagerTestGrandChild1.objects.get()
|
||||||
results = InheritanceManagerTestParent.objects.instance_of(InheritanceManagerTestGrandChild1)
|
results = InheritanceManagerTestParent.objects.instance_of(InheritanceManagerTestGrandChild1)
|
||||||
|
|
@ -445,7 +441,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual(set(children), set(results))
|
self.assertEqual(set(children), set(results))
|
||||||
|
|
||||||
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
|
|
||||||
def test_can_fetch_limited_class_grandchildren(self):
|
def test_can_fetch_limited_class_grandchildren(self):
|
||||||
# Not sure if this is the desired behaviour...?
|
# Not sure if this is the desired behaviour...?
|
||||||
children = InheritanceManagerTestChild1.objects.select_subclasses()
|
children = InheritanceManagerTestChild1.objects.select_subclasses()
|
||||||
|
|
@ -462,7 +457,6 @@ class InheritanceManagerUsingModelsTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual(set([child3] + list(children1)), set(results))
|
self.assertEqual(set([child3] + list(children1)), set(results))
|
||||||
|
|
||||||
@skipUnless(django.VERSION >= (1, 6, 0), "test only applies to Django 1.6+")
|
|
||||||
def test_selecting_multiple_instance_classes_including_grandchildren(self):
|
def test_selecting_multiple_instance_classes_including_grandchildren(self):
|
||||||
child3 = InheritanceManagerTestChild3.objects.create()
|
child3 = InheritanceManagerTestChild3.objects.create()
|
||||||
grandchild1 = InheritanceManagerTestGrandChild1.objects.get()
|
grandchild1 = InheritanceManagerTestGrandChild1.objects.get()
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,9 @@ class CustomDescriptorTests(TestCase):
|
||||||
def test_deferred(self):
|
def test_deferred(self):
|
||||||
instance = ModelWithCustomDescriptor.objects.only('id').get(
|
instance = ModelWithCustomDescriptor.objects.only('id').get(
|
||||||
pk=self.instance.pk)
|
pk=self.instance.pk)
|
||||||
if django.VERSION >= (1, 10):
|
self.assertIn('custom_field', instance.get_deferred_fields())
|
||||||
self.assertIn('custom_field', instance.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertIn('custom_field', instance._deferred_fields)
|
|
||||||
self.assertEqual(instance.custom_field, '1')
|
self.assertEqual(instance.custom_field, '1')
|
||||||
if django.VERSION >= (1, 10):
|
self.assertNotIn('custom_field', instance.get_deferred_fields())
|
||||||
self.assertNotIn('custom_field', instance.get_deferred_fields())
|
|
||||||
else:
|
|
||||||
self.assertNotIn('custom_field', instance._deferred_fields)
|
|
||||||
self.assertEqual(instance.regular_field, 1)
|
self.assertEqual(instance.regular_field, 1)
|
||||||
self.assertEqual(instance.tracked_custom_field, '1')
|
self.assertEqual(instance.tracked_custom_field, '1')
|
||||||
self.assertEqual(instance.tracked_regular_field, 1)
|
self.assertEqual(instance.tracked_regular_field, 1)
|
||||||
|
|
@ -60,12 +54,9 @@ class CustomDescriptorTests(TestCase):
|
||||||
self.assertEqual(instance.tracked_regular_field, 2)
|
self.assertEqual(instance.tracked_regular_field, 2)
|
||||||
|
|
||||||
instance = ModelWithCustomDescriptor.objects.only('id').get(pk=instance.pk)
|
instance = ModelWithCustomDescriptor.objects.only('id').get(pk=instance.pk)
|
||||||
if django.VERSION >= (1, 10):
|
instance.tracked_custom_field = 3
|
||||||
# This fails on 1.8 and 1.9, which is a bug in the deferred field
|
self.assertEqual(instance.tracked_custom_field, '3')
|
||||||
# implementation on those versions.
|
self.assertTrue(instance.tracker.has_changed('tracked_custom_field'))
|
||||||
instance.tracked_custom_field = 3
|
del instance.tracked_custom_field
|
||||||
self.assertEqual(instance.tracked_custom_field, '3')
|
self.assertEqual(instance.tracked_custom_field, '2')
|
||||||
self.assertTrue(instance.tracker.has_changed('tracked_custom_field'))
|
self.assertFalse(instance.tracker.has_changed('tracked_custom_field'))
|
||||||
del instance.tracked_custom_field
|
|
||||||
self.assertEqual(instance.tracked_custom_field, '2')
|
|
||||||
self.assertFalse(instance.tracker.has_changed('tracked_custom_field'))
|
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@ def run(command):
|
||||||
if not settings.configured:
|
if not settings.configured:
|
||||||
settings.configure(**DEFAULT_SETTINGS)
|
settings.configure(**DEFAULT_SETTINGS)
|
||||||
|
|
||||||
# Compatibility with Django 1.7's stricter initialization
|
|
||||||
if hasattr(django, 'setup'):
|
|
||||||
django.setup()
|
|
||||||
|
|
||||||
parent = os.path.dirname(os.path.abspath(__file__))
|
parent = os.path.dirname(os.path.abspath(__file__))
|
||||||
appdir = os.path.join(parent, 'model_utils')
|
appdir = os.path.join(parent, 'model_utils')
|
||||||
os.chdir(appdir)
|
os.chdir(appdir)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue