Add fix + tests for abstract manager inheritance issue with StatusModel

This commit is contained in:
Romain G 2017-01-09 19:02:59 +00:00
parent f56e26b5a9
commit 679af01f26
3 changed files with 57 additions and 1 deletions

View file

@ -64,6 +64,11 @@ def add_status_query_managers(sender, **kwargs):
"""
if not issubclass(sender, StatusModel):
return
if django.VERSION >= (1, 10):
# First, get current manager name...
default_manager = sender._meta.default_manager
for value, display in getattr(sender, 'STATUS', ()):
if _field_exists(sender, value):
raise ImproperlyConfigured(
@ -73,6 +78,10 @@ def add_status_query_managers(sender, **kwargs):
)
sender.add_to_class(value, QueryManager(status=value))
if django.VERSION >= (1, 10):
# ...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):
"""

View file

@ -1,6 +1,7 @@
from __future__ import unicode_literals
from django.db import models
from django.db.models import QuerySet
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
@ -125,6 +126,28 @@ class StatusManagerAdded(StatusModel):
)
class StatusCustomQuerySet(QuerySet):
def active_or_deleted(self):
statuses = ['active', 'deleted']
return self.filter(status__in=statuses)
class AbstractStatusCustomManager(StatusModel):
STATUS = Choices(
("first_choice", _("First choice")),
("second_choice", _("Second choice")),
)
objects = StatusCustomQuerySet.as_manager()
class Meta:
abstract = True
class StatusCustomManager(AbstractStatusCustomManager):
title = models.CharField(max_length=50)
class Post(models.Model):
published = models.BooleanField(default=False)
confirmed = models.BooleanField(default=False)

View file

@ -4,7 +4,7 @@ from freezegun import freeze_time
from django.test.testcases import TestCase
from model_utils.tests.models import Status, StatusPlainTuple
from model_utils.tests.models import Status, StatusPlainTuple, StatusCustomManager
class StatusModelTests(TestCase):
@ -44,3 +44,27 @@ class StatusModelPlainTupleTests(StatusModelTests):
self.model = StatusPlainTuple
self.on_hold = StatusPlainTuple.STATUS[2][0]
self.active = StatusPlainTuple.STATUS[0][0]
class StatusModelDefaultManagerTests(TestCase):
def test_default_manager_is_not_status_model_generated_ones(self):
# Regression test for https://github.com/carljm/django-model-utils/issues/251
# The logic behind order for managers seems to have changed in Django 1.10
# and affects default manager.
# This code was previously failing because the first custom manager (which filters
# with first Choice value, here 'first_choice') generated by StatusModel was
# considered as default manager...
# This situation only happens when we define a model inheriting from an "abstract"
# class which defines an "objects" manager.
StatusCustomManager.objects.create(status='first_choice')
StatusCustomManager.objects.create(status='second_choice')
StatusCustomManager.objects.create(status='second_choice')
# ...which made this count() equal to 1 (only 1 element with status='first_choice')...
self.assertEqual(StatusCustomManager._default_manager.count(), 3)
# ...and this one equal to 0, because of 2 successive filters of 'first_choice'
# (default manager) and 'second_choice' (explicit filter below).
self.assertEqual(StatusCustomManager._default_manager.filter(status='second_choice').count(), 2)