mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Removed a bunch of deprecated code.
This commit is contained in:
parent
a9ac3685fb
commit
6ae66e0153
7 changed files with 9 additions and 277 deletions
|
|
@ -11,7 +11,8 @@ tip (unreleased)
|
|||
.. _BitBucket: https://bitbucket.org/carljm/django-model-utils/overview
|
||||
.. _GitHub: https://github.com/carljm/django-model-utils/
|
||||
|
||||
- Removed deprecated ``ChoiceEnum`` class.
|
||||
- Removed deprecated ``ChoiceEnum``, ``InheritanceCastModel``,
|
||||
``InheritanceCastManager``, and ``manager_from``.
|
||||
|
||||
- Added ``UpdateOrCreateMixin`` for custom queryset subclasses. Thanks Antti
|
||||
Kaihola.
|
||||
|
|
|
|||
15
README.rst
15
README.rst
|
|
@ -305,14 +305,6 @@ it's safe to use as your default manager for the model.
|
|||
internally. Due to `Django bug #16855`_, this currently means that it
|
||||
will override any previous ``select_related`` calls on the ``QuerySet``.
|
||||
|
||||
.. note::
|
||||
``InheritanceManager`` requires Django 1.2 or later. Previous versions of
|
||||
django-model-utils included ``InheritanceCastModel``, an alternative (and
|
||||
inferior) approach to this problem that is Django 1.1
|
||||
compatible. ``InheritanceCastModel`` will remain in django-model-utils
|
||||
until support for Django 1.1 is removed, but it is no longer documented and
|
||||
its use in new code is discouraged.
|
||||
|
||||
.. _contributed by Jeff Elmore: http://jeffelmore.org/2010/11/11/automatic-downcasting-of-inherited-models-in-django/
|
||||
.. _Django bug #16855: https://code.djangoproject.com/ticket/16855
|
||||
|
||||
|
|
@ -396,13 +388,6 @@ directly on the manager::
|
|||
Post.objects.published()
|
||||
Post.objects.by_author(user=request.user).unpublished()
|
||||
|
||||
.. note::
|
||||
|
||||
Previous versions of django-model-utils included ``manager_from``, a
|
||||
function that solved the same problem as ``PassThroughManager``. The
|
||||
``manager_from`` approach created dynamic ``QuerySet`` subclasses on the
|
||||
fly, which broke pickling of those querysets. For this reason,
|
||||
``PassThroughManager`` is recommended instead.
|
||||
|
||||
|
||||
UpdateOrCreateMixin
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ from datetime import datetime
|
|||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from model_utils import Choices
|
||||
|
||||
|
||||
try:
|
||||
from django.utils.timezone import now as now
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
from types import ClassType
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import IntegrityError, models, transaction
|
||||
from django.db.models.fields.related import OneToOneField
|
||||
from django.db.models.manager import Manager
|
||||
from django.db.models.query import QuerySet
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
|
|
@ -67,26 +63,6 @@ class InheritanceManager(models.Manager):
|
|||
return self.get_query_set().select_subclasses().get(*args, **kwargs)
|
||||
|
||||
|
||||
class InheritanceCastMixin(object):
|
||||
def cast(self):
|
||||
results = tuple(self.values_list('pk', 'real_type'))
|
||||
type_to_pks = {}
|
||||
for pk, real_type_id in results:
|
||||
type_to_pks.setdefault(real_type_id, []).append(pk)
|
||||
content_types = ContentType.objects.in_bulk(type_to_pks.keys())
|
||||
pk_to_child = {}
|
||||
for real_type_id, pks in type_to_pks.iteritems():
|
||||
content_type = content_types[real_type_id]
|
||||
child_type = content_type.model_class()
|
||||
children = child_type._default_manager.in_bulk(pks)
|
||||
for pk, child in children.iteritems():
|
||||
pk_to_child[pk] = child
|
||||
children = []
|
||||
# sort children into same order as parents where returned
|
||||
for pk, real_type_id in results:
|
||||
children.append(pk_to_child[pk])
|
||||
return children
|
||||
|
||||
|
||||
class QueryManager(models.Manager):
|
||||
use_for_related_fields = True
|
||||
|
|
@ -180,62 +156,6 @@ def unpickle_pass_through_manager_for_queryset_class(base, queryset_cls):
|
|||
return cls.__new__(cls)
|
||||
|
||||
|
||||
def manager_from(*mixins, **kwds):
|
||||
"""
|
||||
Returns a Manager instance with extra methods, also available and
|
||||
chainable on generated querysets.
|
||||
|
||||
(By George Sakkis, originally posted at
|
||||
http://djangosnippets.org/snippets/2117/)
|
||||
|
||||
:param mixins: Each ``mixin`` can be either a class or a function. The
|
||||
generated manager and associated queryset subclasses extend the mixin
|
||||
classes and include the mixin functions (as methods).
|
||||
|
||||
:keyword queryset_cls: The base queryset class to extend from
|
||||
(``django.db.models.query.QuerySet`` by default).
|
||||
|
||||
:keyword manager_cls: The base manager class to extend from
|
||||
(``django.db.models.manager.Manager`` by default).
|
||||
|
||||
"""
|
||||
warnings.warn(
|
||||
"manager_from is pending deprecation; use PassThroughManager instead.",
|
||||
PendingDeprecationWarning,
|
||||
stacklevel=2)
|
||||
# collect separately the mixin classes and methods
|
||||
bases = [kwds.get('queryset_cls', QuerySet)]
|
||||
methods = {}
|
||||
for mixin in mixins:
|
||||
if isinstance(mixin, (ClassType, type)):
|
||||
bases.append(mixin)
|
||||
else:
|
||||
try: methods[mixin.__name__] = mixin
|
||||
except AttributeError:
|
||||
raise TypeError('Mixin must be class or function, not %s' %
|
||||
mixin.__class__)
|
||||
# create the QuerySet subclass
|
||||
id = hash(mixins + tuple(kwds.iteritems()))
|
||||
new_queryset_cls = type('Queryset_%d' % id, tuple(bases), methods)
|
||||
# create the Manager subclass
|
||||
bases[0] = manager_cls = kwds.get('manager_cls', Manager)
|
||||
new_manager_cls = type('Manager_%d' % id, tuple(bases), methods)
|
||||
# and finally override new manager's get_query_set
|
||||
super_get_query_set = manager_cls.get_query_set
|
||||
def get_query_set(self):
|
||||
# first honor the super manager's get_query_set
|
||||
qs = super_get_query_set(self)
|
||||
# and then try to bless the returned queryset by reassigning it to the
|
||||
# newly created Queryset class, though this may not be feasible
|
||||
if not issubclass(new_queryset_cls, qs.__class__):
|
||||
raise TypeError('QuerySet subclass conflict: cannot determine a '
|
||||
'unique class for queryset instance')
|
||||
qs.__class__ = new_queryset_cls
|
||||
return qs
|
||||
new_manager_cls.get_query_set = get_query_set
|
||||
return new_manager_cls()
|
||||
|
||||
|
||||
class UpdateOrCreateMixin(object):
|
||||
def update_or_create(self, **kwargs):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
import warnings
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from model_utils.managers import manager_from, InheritanceCastMixin, \
|
||||
QueryManager
|
||||
from model_utils.managers import QueryManager
|
||||
from model_utils.fields import AutoCreatedField, AutoLastModifiedField, \
|
||||
StatusField, MonitorField
|
||||
|
||||
|
|
@ -19,42 +15,6 @@ except ImportError:
|
|||
now = datetime.now
|
||||
|
||||
|
||||
class InheritanceCastModel(models.Model):
|
||||
"""
|
||||
An abstract base class that provides a ``real_type`` FK to ContentType.
|
||||
|
||||
For use in trees of inherited models, to be able to downcast
|
||||
parent instances to their child types.
|
||||
|
||||
Pending deprecation; use InheritanceManager instead.
|
||||
|
||||
"""
|
||||
real_type = models.ForeignKey(ContentType, editable=False, null=True)
|
||||
|
||||
objects = manager_from(InheritanceCastMixin)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn(
|
||||
"InheritanceCastModel is pending deprecation. "
|
||||
"Use InheritanceManager instead.",
|
||||
PendingDeprecationWarning,
|
||||
stacklevel=2)
|
||||
super(InheritanceCastModel, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.id:
|
||||
self.real_type = self._get_real_type()
|
||||
super(InheritanceCastModel, self).save(*args, **kwargs)
|
||||
|
||||
def _get_real_type(self):
|
||||
return ContentType.objects.get_for_model(type(self))
|
||||
|
||||
def cast(self):
|
||||
return self.real_type.get_object_for_this_type(pk=self.pk)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class TimeStampedModel(models.Model):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,34 +1,13 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from model_utils.models import InheritanceCastModel, TimeStampedModel, StatusModel, TimeFramedModel
|
||||
from model_utils.managers import QueryManager, manager_from, InheritanceManager, PassThroughManager, UpdateOrCreateMixin
|
||||
from model_utils.models import TimeStampedModel, StatusModel, TimeFramedModel
|
||||
from model_utils.managers import QueryManager, InheritanceManager, PassThroughManager, UpdateOrCreateMixin
|
||||
from model_utils.fields import SplitField, MonitorField
|
||||
from model_utils import Choices
|
||||
|
||||
|
||||
|
||||
class InheritParent(InheritanceCastModel):
|
||||
non_related_field_using_descriptor = models.FileField(upload_to="test")
|
||||
normal_field = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritChild(InheritParent):
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
|
||||
normal_field_2 = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritChild2(InheritParent):
|
||||
non_related_field_using_descriptor_3 = models.FileField(upload_to="test")
|
||||
normal_field_3 = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestRelated(models.Model):
|
||||
pass
|
||||
|
||||
|
|
@ -178,19 +157,6 @@ class FeaturedManager(models.Manager):
|
|||
|
||||
|
||||
|
||||
class Entry(models.Model):
|
||||
author = models.CharField(max_length=20)
|
||||
published = models.BooleanField()
|
||||
feature = models.BooleanField(default=False)
|
||||
|
||||
objects = manager_from(AuthorMixin, PublishedMixin, unpublished)
|
||||
broken = manager_from(PublishedMixin, manager_cls=FeaturedManager)
|
||||
featured = manager_from(PublishedMixin,
|
||||
manager_cls=FeaturedManager,
|
||||
queryset_cls=ByAuthorQuerySet)
|
||||
|
||||
|
||||
|
||||
class DudeQuerySet(models.query.QuerySet):
|
||||
def abiding(self):
|
||||
return self.filter(abides=True)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import with_statement
|
||||
|
||||
import pickle, warnings
|
||||
import pickle
|
||||
|
||||
from datetime import date, datetime, timedelta
|
||||
|
||||
|
|
@ -9,18 +9,16 @@ from django.db.models.fields import FieldDoesNotExist
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from model_utils import Choices
|
||||
from model_utils.fields import get_excerpt, MonitorField
|
||||
from model_utils.managers import QueryManager, manager_from
|
||||
from model_utils.managers import QueryManager
|
||||
from model_utils.models import StatusModel, TimeFramedModel
|
||||
from model_utils.tests.models import (
|
||||
InheritParent, InheritChild, InheritChild2, InheritanceManagerTestRelated,
|
||||
InheritanceManagerTestRelated,
|
||||
InheritanceManagerTestParent, InheritanceManagerTestChild1,
|
||||
InheritanceManagerTestChild2, TimeStamp, Post, Article, Status,
|
||||
StatusPlainTuple, TimeFrame, Monitored, StatusManagerAdded,
|
||||
TimeFrameManagerAdded, Entry, Dude, SplitFieldAbstractParent, Car, Spot,
|
||||
TimeFrameManagerAdded, Dude, SplitFieldAbstractParent, Car, Spot,
|
||||
Person)
|
||||
|
||||
|
||||
|
|
@ -277,57 +275,6 @@ class IdentifierChoicesTests(ChoicesTests):
|
|||
"(2, 'DELETED', 'is deleted'))")
|
||||
|
||||
|
||||
class InheritanceCastModelTests(TestCase):
|
||||
def setUp(self):
|
||||
self.parent = InheritParent.objects.create()
|
||||
self.child = InheritChild.objects.create()
|
||||
|
||||
|
||||
def test_parent_real_type(self):
|
||||
self.assertEquals(self.parent.real_type,
|
||||
ContentType.objects.get_for_model(InheritParent))
|
||||
|
||||
|
||||
def test_child_real_type(self):
|
||||
self.assertEquals(self.child.real_type,
|
||||
ContentType.objects.get_for_model(InheritChild))
|
||||
|
||||
|
||||
def test_cast(self):
|
||||
obj = InheritParent.objects.get(pk=self.child.pk).cast()
|
||||
self.assertEquals(obj.__class__, InheritChild)
|
||||
|
||||
|
||||
def test_pending_deprecation(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
InheritParent()
|
||||
self.assertEqual(len(w), 1)
|
||||
assert issubclass(w[-1].category, PendingDeprecationWarning)
|
||||
|
||||
|
||||
|
||||
class InheritanceCastQuerysetTests(TestCase):
|
||||
def setUp(self):
|
||||
self.child = InheritChild.objects.create()
|
||||
self.child2 = InheritChild2.objects.create()
|
||||
|
||||
|
||||
def test_cast_manager(self):
|
||||
self.assertEquals(set(InheritParent.objects.cast()),
|
||||
set([self.child, self.child2]))
|
||||
|
||||
|
||||
def test_cast(self):
|
||||
parent = InheritParent.objects.create()
|
||||
obj = InheritParent.objects.filter(pk=self.child.pk).cast()[0]
|
||||
self.assertEquals(obj.__class__, InheritChild)
|
||||
self.assertEquals(set(InheritChild2.objects.all().cast()),
|
||||
set([self.child2]))
|
||||
self.assertEquals(set(InheritParent.objects.all().cast()),
|
||||
set([parent, self.child, self.child2]))
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTests(TestCase):
|
||||
def setUp(self):
|
||||
|
|
@ -579,51 +526,6 @@ if introspector:
|
|||
|
||||
|
||||
|
||||
class ManagerFromTests(TestCase):
|
||||
def setUp(self):
|
||||
Entry.objects.create(author='George', published=True)
|
||||
Entry.objects.create(author='George', published=False)
|
||||
Entry.objects.create(author='Paul', published=True, feature=True)
|
||||
|
||||
|
||||
def test_chaining(self):
|
||||
self.assertEqual(Entry.objects.by_author('George').published().count(),
|
||||
1)
|
||||
|
||||
|
||||
def test_function(self):
|
||||
self.assertEqual(Entry.objects.unpublished().count(), 1)
|
||||
|
||||
|
||||
def test_typecheck(self):
|
||||
self.assertRaises(TypeError, manager_from, 'somestring')
|
||||
|
||||
|
||||
def test_custom_get_query_set(self):
|
||||
self.assertEqual(Entry.featured.published().count(), 1)
|
||||
|
||||
|
||||
def test_cant_reconcile_qs_class(self):
|
||||
self.assertRaises(TypeError, Entry.broken.all)
|
||||
|
||||
|
||||
def test_queryset_pickling_fails(self):
|
||||
qs = Entry.objects.all()
|
||||
def dump_load():
|
||||
pqs = pickle.dumps(qs)
|
||||
pickle.loads(pqs)
|
||||
self.assertRaises(pickle.PicklingError, dump_load)
|
||||
|
||||
|
||||
def test_pending_deprecation(self):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
manager_from()
|
||||
self.assertEqual(len(w), 1)
|
||||
assert issubclass(w[-1].category, PendingDeprecationWarning)
|
||||
|
||||
|
||||
|
||||
class PassThroughManagerTests(TestCase):
|
||||
def setUp(self):
|
||||
Dude.objects.create(name='The Dude', abides=True, has_rug=False)
|
||||
|
|
|
|||
Loading…
Reference in a new issue