mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-03-16 20:00:23 +00:00
Fix issue when extend QuerySet and Manager - fixes #249
This commit is contained in:
parent
0febeae9ee
commit
0efaad1218
5 changed files with 64 additions and 35 deletions
|
|
@ -192,11 +192,16 @@ class InheritanceQuerySetMixin(object):
|
|||
return levels
|
||||
|
||||
|
||||
class InheritanceQuerySet(InheritanceQuerySetMixin, QuerySet):
|
||||
pass
|
||||
|
||||
|
||||
class InheritanceManagerMixin(object):
|
||||
use_for_related_fields = True
|
||||
_queryset_class = InheritanceQuerySet
|
||||
|
||||
def get_queryset(self):
|
||||
return InheritanceQuerySet(self.model)
|
||||
return self._queryset_class(self.model)
|
||||
|
||||
get_query_set = get_queryset
|
||||
|
||||
|
|
@ -207,10 +212,6 @@ class InheritanceManagerMixin(object):
|
|||
return self.get_queryset().get_subclass(*args, **kwargs)
|
||||
|
||||
|
||||
class InheritanceQuerySet(InheritanceQuerySetMixin, QuerySet):
|
||||
pass
|
||||
|
||||
|
||||
class InheritanceManager(InheritanceManagerMixin, models.Manager):
|
||||
pass
|
||||
|
||||
|
|
@ -265,6 +266,7 @@ class SoftDeletableManager(models.Manager):
|
|||
Manager that limits the queryset by default to show only not removed
|
||||
instances of model.
|
||||
"""
|
||||
use_for_related_fields = True
|
||||
_queryset_class = SoftDeletableQuerySet
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
@ -275,6 +277,6 @@ class SoftDeletableManager(models.Manager):
|
|||
if hasattr(self, '_hints'):
|
||||
kwargs['hints'] = self._hints
|
||||
|
||||
return SoftDeletableQuerySet(**kwargs).filter(is_removed=False)
|
||||
return self._queryset_class(**kwargs).filter(is_removed=False)
|
||||
|
||||
get_query_set = get_queryset
|
||||
|
|
|
|||
15
model_utils/tests/managers.py
Normal file
15
model_utils/tests/managers.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from model_utils.managers import SoftDeletableQuerySet, SoftDeletableManager
|
||||
|
||||
|
||||
class CustomSoftDeleteQuerySet(SoftDeletableQuerySet):
|
||||
def only_read(self):
|
||||
return self.filter(is_read=True)
|
||||
|
||||
|
||||
class CustomSoftDeleteManager(SoftDeletableManager):
|
||||
_queryset_class = CustomSoftDeleteQuerySet
|
||||
|
||||
def only_read(self):
|
||||
return self.get_queryset().only_read()
|
||||
|
|
@ -4,25 +4,24 @@ from django.db import models
|
|||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from model_utils import Choices
|
||||
from model_utils.fields import SplitField, MonitorField, StatusField
|
||||
from model_utils.managers import QueryManager, InheritanceManager
|
||||
from model_utils.models import (
|
||||
SoftDeletableModel,
|
||||
StatusModel,
|
||||
TimeFramedModel,
|
||||
TimeStampedModel,
|
||||
)
|
||||
from model_utils.tracker import FieldTracker, ModelTracker
|
||||
from model_utils.managers import QueryManager, InheritanceManager
|
||||
from model_utils.fields import SplitField, MonitorField, StatusField
|
||||
from model_utils.tests.fields import MutableField
|
||||
from model_utils import Choices
|
||||
|
||||
from model_utils.tests.managers import CustomSoftDeleteManager
|
||||
from model_utils.tracker import FieldTracker, ModelTracker
|
||||
|
||||
|
||||
class InheritanceManagerTestRelated(models.Model):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class InheritanceManagerTestParent(models.Model):
|
||||
# FileField is just a handy descriptor-using field. Refs #6.
|
||||
|
|
@ -40,8 +39,7 @@ class InheritanceManagerTestParent(models.Model):
|
|||
return "%s(%s)" % (
|
||||
self.__class__.__name__[len('InheritanceManagerTest'):],
|
||||
self.pk,
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
|
||||
class InheritanceManagerTestChild1(InheritanceManagerTestParent):
|
||||
|
|
@ -50,23 +48,19 @@ class InheritanceManagerTestChild1(InheritanceManagerTestParent):
|
|||
objects = InheritanceManager()
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestGrandChild1(InheritanceManagerTestChild1):
|
||||
text_field = models.TextField()
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestGrandChild1_2(InheritanceManagerTestChild1):
|
||||
text_field = models.TextField()
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestChild2(InheritanceManagerTestParent):
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
|
||||
normal_field_2 = models.TextField()
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestChild3(InheritanceManagerTestParent):
|
||||
parent_ptr = models.OneToOneField(
|
||||
InheritanceManagerTestParent, related_name='manual_onetoone',
|
||||
|
|
@ -77,29 +71,24 @@ class TimeStamp(TimeStampedModel):
|
|||
pass
|
||||
|
||||
|
||||
|
||||
class TimeFrame(TimeFramedModel):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class TimeFrameManagerAdded(TimeFramedModel):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class Monitored(models.Model):
|
||||
name = models.CharField(max_length=25)
|
||||
name_changed = MonitorField(monitor="name")
|
||||
|
||||
|
||||
|
||||
class MonitorWhen(models.Model):
|
||||
name = models.CharField(max_length=25)
|
||||
name_changed = MonitorField(monitor="name", when=["Jose", "Maria"])
|
||||
|
||||
|
||||
|
||||
class MonitorWhenEmpty(models.Model):
|
||||
name = models.CharField(max_length=25)
|
||||
name_changed = MonitorField(monitor="name", when=[])
|
||||
|
|
@ -120,7 +109,6 @@ class Status(StatusModel):
|
|||
)
|
||||
|
||||
|
||||
|
||||
class StatusPlainTuple(StatusModel):
|
||||
STATUS = (
|
||||
("active", _("active")),
|
||||
|
|
@ -129,7 +117,6 @@ class StatusPlainTuple(StatusModel):
|
|||
)
|
||||
|
||||
|
||||
|
||||
class StatusManagerAdded(StatusModel):
|
||||
STATUS = (
|
||||
("active", _("active")),
|
||||
|
|
@ -138,7 +125,6 @@ class StatusManagerAdded(StatusModel):
|
|||
)
|
||||
|
||||
|
||||
|
||||
class Post(models.Model):
|
||||
published = models.BooleanField(default=False)
|
||||
confirmed = models.BooleanField(default=False)
|
||||
|
|
@ -154,22 +140,18 @@ class Post(models.Model):
|
|||
ordering = ("order",)
|
||||
|
||||
|
||||
|
||||
class Article(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
body = SplitField()
|
||||
|
||||
|
||||
|
||||
class SplitFieldAbstractParent(models.Model):
|
||||
content = SplitField()
|
||||
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
|
||||
class NoRendered(models.Model):
|
||||
"""
|
||||
Test that the no_excerpt_field keyword arg works. This arg should
|
||||
|
|
@ -179,29 +161,24 @@ class NoRendered(models.Model):
|
|||
body = SplitField(no_excerpt_field=True)
|
||||
|
||||
|
||||
|
||||
class AuthorMixin(object):
|
||||
def by_author(self, name):
|
||||
return self.filter(author=name)
|
||||
|
||||
|
||||
|
||||
class PublishedMixin(object):
|
||||
def published(self):
|
||||
return self.filter(published=True)
|
||||
|
||||
|
||||
|
||||
def unpublished(self):
|
||||
return self.filter(published=False)
|
||||
|
||||
|
||||
|
||||
class ByAuthorQuerySet(models.query.QuerySet, AuthorMixin):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class FeaturedManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
kwargs = {}
|
||||
|
|
@ -326,3 +303,9 @@ class SoftDeletable(SoftDeletableModel):
|
|||
name = models.CharField(max_length=20)
|
||||
|
||||
all_objects = models.Manager()
|
||||
|
||||
|
||||
class CustomSoftDelete(SoftDeletableModel):
|
||||
is_read = models.BooleanField(default=False)
|
||||
|
||||
objects = CustomSoftDeleteManager()
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
from .test_inheritance_manager import *
|
||||
from .test_query_manager import *
|
||||
from .test_status_manager import *
|
||||
from .test_softdelete_manager import *
|
||||
|
|
|
|||
28
model_utils/tests/test_managers/test_softdelete_manager.py
Normal file
28
model_utils/tests/test_managers/test_softdelete_manager.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from model_utils.tests.models import CustomSoftDelete
|
||||
|
||||
|
||||
class CustomSoftDeleteManagerTests(TestCase):
|
||||
|
||||
def test_custom_manager_empty(self):
|
||||
qs = CustomSoftDelete.objects.only_read()
|
||||
self.assertEqual(qs.count(), 0)
|
||||
|
||||
def test_custom_qs_empty(self):
|
||||
qs = CustomSoftDelete.objects.all().only_read()
|
||||
self.assertEqual(qs.count(), 0)
|
||||
|
||||
def test_is_read(self):
|
||||
for is_read in [True, False, True, False]:
|
||||
CustomSoftDelete.objects.create(is_read=is_read)
|
||||
qs = CustomSoftDelete.objects.only_read()
|
||||
self.assertEqual(qs.count(), 2)
|
||||
|
||||
def test_is_read_removed(self):
|
||||
for is_read, is_removed in [(True, True), (True, False), (False, False), (False, True)]:
|
||||
CustomSoftDelete.objects.create(is_read=is_read, is_removed=is_removed)
|
||||
qs = CustomSoftDelete.objects.only_read()
|
||||
self.assertEqual(qs.count(), 1)
|
||||
Loading…
Reference in a new issue