mirror of
https://github.com/Hopiu/django-model-utils.git
synced 2026-04-26 13:54:43 +00:00
Added use_for_related_fields=True to InheritanceManager. Fixes #8. Thanks munhitsu for the report.
Note that the tests added for this feature pass even without the change to InheritanceManager, because use_for_related_fields is broken in Django and always acts as if True for reverse FKs and M2Ms. (http://code.djangoproject.com/ticket/14891)
This commit is contained in:
parent
69d0985db1
commit
5c5abdce23
3 changed files with 109 additions and 32 deletions
|
|
@ -35,6 +35,8 @@ class InheritanceQuerySet(QuerySet):
|
|||
yield obj
|
||||
|
||||
class InheritanceManager(models.Manager):
|
||||
use_for_related_fields = True
|
||||
|
||||
def get_query_set(self):
|
||||
return InheritanceQuerySet(self.model)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,72 +6,106 @@ from model_utils.managers import QueryManager, manager_from, InheritanceManager,
|
|||
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')
|
||||
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')
|
||||
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')
|
||||
non_related_field_using_descriptor_3 = models.FileField(upload_to="test")
|
||||
normal_field_3 = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestRelated(models.Model):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestParent(models.Model):
|
||||
# test for #6
|
||||
# I'm using FileField, because it will always use descriptor
|
||||
non_related_field_using_descriptor = models.FileField(upload_to='test')
|
||||
# FileField is just a handy descriptor-using field. Refs #6.
|
||||
non_related_field_using_descriptor = models.FileField(upload_to="test")
|
||||
related = models.ForeignKey(
|
||||
InheritanceManagerTestRelated, related_name="imtests", null=True)
|
||||
normal_field = models.TextField()
|
||||
objects = InheritanceManager()
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestChild1(InheritanceManagerTestParent):
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to='test')
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
|
||||
normal_field_2 = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class InheritanceManagerTestChild2(InheritanceManagerTestParent):
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to='test')
|
||||
non_related_field_using_descriptor_2 = models.FileField(upload_to="test")
|
||||
normal_field_2 = models.TextField()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
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')
|
||||
name_changed = MonitorField(monitor="name")
|
||||
|
||||
|
||||
|
||||
class Status(StatusModel):
|
||||
STATUS = Choices(
|
||||
('active', _('active')),
|
||||
('deleted', _('deleted')),
|
||||
('on_hold', _('on hold')),
|
||||
("active", _("active")),
|
||||
("deleted", _("deleted")),
|
||||
("on_hold", _("on hold")),
|
||||
)
|
||||
|
||||
|
||||
|
||||
class StatusPlainTuple(StatusModel):
|
||||
STATUS = (
|
||||
('active', _('active')),
|
||||
('deleted', _('deleted')),
|
||||
('on_hold', _('on hold')),
|
||||
("active", _("active")),
|
||||
("deleted", _("deleted")),
|
||||
("on_hold", _("on hold")),
|
||||
)
|
||||
|
||||
|
||||
|
||||
class StatusManagerAdded(StatusModel):
|
||||
STATUS = (
|
||||
('active', _('active')),
|
||||
('deleted', _('deleted')),
|
||||
('on_hold', _('on hold')),
|
||||
("active", _("active")),
|
||||
("deleted", _("deleted")),
|
||||
("on_hold", _("on hold")),
|
||||
)
|
||||
|
||||
|
||||
|
||||
class Post(models.Model):
|
||||
published = models.BooleanField()
|
||||
confirmed = models.BooleanField()
|
||||
|
|
@ -81,15 +115,19 @@ class Post(models.Model):
|
|||
public = QueryManager(published=True)
|
||||
public_confirmed = QueryManager(models.Q(published=True) &
|
||||
models.Q(confirmed=True))
|
||||
public_reversed = QueryManager(published=True).order_by('-order')
|
||||
public_reversed = QueryManager(published=True).order_by("-order")
|
||||
|
||||
class Meta:
|
||||
ordering = ('order',)
|
||||
ordering = ("order",)
|
||||
|
||||
|
||||
|
||||
class Article(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
body = SplitField()
|
||||
|
||||
|
||||
|
||||
class NoRendered(models.Model):
|
||||
"""
|
||||
Test that the no_excerpt_field keyword arg works. This arg should
|
||||
|
|
@ -98,27 +136,39 @@ 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_query_set(self):
|
||||
kwargs = {}
|
||||
if hasattr(self, '_db'):
|
||||
kwargs['using'] = self._db
|
||||
if hasattr(self, "_db"):
|
||||
kwargs["using"] = self._db
|
||||
return ByAuthorQuerySet(self.model, **kwargs).filter(feature=True)
|
||||
|
||||
|
||||
|
||||
class Entry(models.Model):
|
||||
author = models.CharField(max_length=20)
|
||||
published = models.BooleanField()
|
||||
|
|
@ -130,6 +180,8 @@ class Entry(models.Model):
|
|||
manager_cls=FeaturedManager,
|
||||
queryset_cls=ByAuthorQuerySet)
|
||||
|
||||
|
||||
|
||||
class DudeQuerySet(models.query.QuerySet):
|
||||
def abiding(self):
|
||||
return self.filter(abides=True)
|
||||
|
|
@ -143,16 +195,20 @@ class DudeQuerySet(models.query.QuerySet):
|
|||
def by_name(self, name):
|
||||
return self.filter(name__iexact=name)
|
||||
|
||||
|
||||
|
||||
class AbidingManager(PassThroughManager):
|
||||
def get_query_set(self):
|
||||
return DudeQuerySet(self.model).abiding()
|
||||
|
||||
def get_stats(self):
|
||||
return {
|
||||
'abiding_count': self.count(),
|
||||
'rug_count': self.rug_positive().count(),
|
||||
"abiding_count": self.count(),
|
||||
"rug_count": self.rug_positive().count(),
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Dude(models.Model):
|
||||
abides = models.BooleanField(default=True)
|
||||
name = models.CharField(max_length=20)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
from __future__ import with_statement
|
||||
|
||||
import pickle, sys, warnings
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import django
|
||||
from django.test import TestCase
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
|
@ -16,10 +17,11 @@ from model_utils.fields import get_excerpt, MonitorField
|
|||
from model_utils.managers import QueryManager, manager_from
|
||||
from model_utils.models import StatusModel, TimeFramedModel
|
||||
from model_utils.tests.models import (
|
||||
InheritParent, InheritChild, InheritChild2, InheritanceManagerTestParent,
|
||||
InheritanceManagerTestChild1, InheritanceManagerTestChild2,
|
||||
TimeStamp, Post, Article, Status, StatusPlainTuple, TimeFrame, Monitored,
|
||||
StatusManagerAdded, TimeFrameManagerAdded, Entry, Dude)
|
||||
InheritParent, InheritChild, InheritChild2, InheritanceManagerTestRelated,
|
||||
InheritanceManagerTestParent, InheritanceManagerTestChild1,
|
||||
InheritanceManagerTestChild2, TimeStamp, Post, Article, Status,
|
||||
StatusPlainTuple, TimeFrame, Monitored, StatusManagerAdded,
|
||||
TimeFrameManagerAdded, Entry, Dude)
|
||||
|
||||
|
||||
|
||||
|
|
@ -316,8 +318,12 @@ if django.VERSION >= (1, 2):
|
|||
self.child2 = InheritanceManagerTestChild2.objects.create()
|
||||
|
||||
|
||||
def get_manager(self):
|
||||
return InheritanceManagerTestParent.objects
|
||||
|
||||
|
||||
def test_normal(self):
|
||||
self.assertEquals(set(InheritanceManagerTestParent.objects.all()),
|
||||
self.assertEquals(set(self.get_manager().all()),
|
||||
set([
|
||||
InheritanceManagerTestParent(pk=self.child1.pk),
|
||||
InheritanceManagerTestParent(pk=self.child2.pk),
|
||||
|
|
@ -326,18 +332,31 @@ if django.VERSION >= (1, 2):
|
|||
|
||||
def test_select_all_subclasses(self):
|
||||
self.assertEquals(
|
||||
set(InheritanceManagerTestParent.objects.select_subclasses()),
|
||||
set(self.get_manager().select_subclasses()),
|
||||
set([self.child1, self.child2]))
|
||||
|
||||
|
||||
def test_select_specific_subclasses(self):
|
||||
self.assertEquals(
|
||||
set(InheritanceManagerTestParent.objects.select_subclasses(
|
||||
set(self.get_manager().select_subclasses(
|
||||
"inheritancemanagertestchild1")),
|
||||
set([self.child1,
|
||||
InheritanceManagerTestParent(pk=self.child2.pk)]))
|
||||
|
||||
|
||||
class InheritanceManagerRelatedTests(InheritanceManagerTests):
|
||||
def setUp(self):
|
||||
self.related = InheritanceManagerTestRelated.objects.create()
|
||||
self.child1 = InheritanceManagerTestChild1.objects.create(
|
||||
related=self.related)
|
||||
self.child2 = InheritanceManagerTestChild2.objects.create(
|
||||
related=self.related)
|
||||
|
||||
|
||||
def get_manager(self):
|
||||
return self.related.imtests
|
||||
|
||||
|
||||
|
||||
class TimeStampedModelTests(TestCase):
|
||||
def test_created(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue