Fix reverse relation support for ___ filter operator
parent
137139f2bb
commit
b0657ef9c7
|
|
@ -1,6 +1,13 @@
|
||||||
Changelog
|
Changelog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
Version 0.8.1 (2015-12-29)
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
* Fixed support for reverse relations for ``relname___field`` when the field starts with an ``_`` character.
|
||||||
|
Otherwise, the query will be interpreted as subclass lookup (``ClassName___field``).
|
||||||
|
|
||||||
|
|
||||||
Version 0.8 (2015-12-28)
|
Version 0.8 (2015-12-28)
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,25 @@
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q, FieldDoesNotExist
|
from django.db.models import Q, FieldDoesNotExist
|
||||||
|
|
||||||
from django.db.models.fields.related import RelatedField # Django 1.8
|
from django.db.models.fields.related import RelatedField
|
||||||
|
if django.VERSION < (1, 6):
|
||||||
|
# There was no common base class in Django 1.5, mention all variants here.
|
||||||
|
from django.db.models.fields.related import RelatedObject, ManyToOneRel, ManyToManyRel
|
||||||
|
REL_FIELD_CLASSES = (RelatedField, RelatedObject, ManyToOneRel, ManyToManyRel) # Leaving GenericRel out.
|
||||||
|
elif django.VERSION < (1, 8):
|
||||||
|
# As of Django 1.6 there is a ForeignObjectRel.
|
||||||
|
from django.db.models.fields.related import ForeignObjectRel, RelatedObject
|
||||||
|
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel, RelatedObject)
|
||||||
|
else:
|
||||||
|
# As of Django 1.8 the base class serves everything. RelatedObject is gone.
|
||||||
|
from django.db.models.fields.related import ForeignObjectRel
|
||||||
|
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel)
|
||||||
|
|
||||||
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
|
@ -154,9 +168,13 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
# Test whether it's actually a regular relation__ _fieldname (the field starting with an _)
|
# Test whether it's actually a regular relation__ _fieldname (the field starting with an _)
|
||||||
# so no tripple ClassName___field was intended.
|
# so no tripple ClassName___field was intended.
|
||||||
try:
|
try:
|
||||||
# rel = (field_object, model, direct, m2m)
|
if django.VERSION >= (1, 8):
|
||||||
|
# This also retreives M2M relations now (including reverse foreign key relations)
|
||||||
field = queryset_model._meta.get_field(classname)
|
field = queryset_model._meta.get_field(classname)
|
||||||
if isinstance(field, RelatedField):
|
else:
|
||||||
|
field = queryset_model._meta.get_field_by_name(classname)[0]
|
||||||
|
|
||||||
|
if isinstance(field, REL_FIELD_CLASSES):
|
||||||
# Can also test whether the field exists in the related object to avoid ambiguity between
|
# Can also test whether the field exists in the related object to avoid ambiguity between
|
||||||
# class names and field names, but that never happens when your class names are in CamelCase.
|
# class names and field names, but that never happens when your class names are in CamelCase.
|
||||||
return field_path # No exception raised, field does exist.
|
return field_path # No exception raised, field does exist.
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,8 @@ class ModelUnderRelParent(PolymorphicModel):
|
||||||
|
|
||||||
|
|
||||||
class ModelUnderRelChild(PolymorphicModel):
|
class ModelUnderRelChild(PolymorphicModel):
|
||||||
parent = models.ForeignKey(ModelUnderRelParent)
|
parent = models.ForeignKey(ModelUnderRelParent, related_name='children')
|
||||||
|
_private2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class MyManagerQuerySet(PolymorphicQuerySet):
|
class MyManagerQuerySet(PolymorphicQuerySet):
|
||||||
|
|
@ -734,12 +735,20 @@ class PolymorphicTests(TestCase):
|
||||||
|
|
||||||
def test_polymorphic___filter_field(self):
|
def test_polymorphic___filter_field(self):
|
||||||
p = ModelUnderRelParent.objects.create(_private=True, field1='AA')
|
p = ModelUnderRelParent.objects.create(_private=True, field1='AA')
|
||||||
ModelUnderRelChild.objects.create(parent=p)
|
ModelUnderRelChild.objects.create(parent=p, _private2=True)
|
||||||
|
|
||||||
# The "___" filter should also parse to "parent" -> "_private" as fallback.
|
# The "___" filter should also parse to "parent" -> "_private" as fallback.
|
||||||
objects = ModelUnderRelChild.objects.filter(parent___private=True)
|
objects = ModelUnderRelChild.objects.filter(parent___private=True)
|
||||||
self.assertEqual(len(objects), 1)
|
self.assertEqual(len(objects), 1)
|
||||||
|
|
||||||
|
def test_polymorphic___filter_reverse_field(self):
|
||||||
|
p = ModelUnderRelParent.objects.create(_private=True, field1='BB')
|
||||||
|
ModelUnderRelChild.objects.create(parent=p, _private2=True)
|
||||||
|
|
||||||
|
# Also test for reverse relations
|
||||||
|
objects = ModelUnderRelParent.objects.filter(children___private2=True)
|
||||||
|
self.assertEqual(len(objects), 1)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue