diff --git a/polymorphic/__init__.py b/polymorphic/__init__.py index 15e3430..9491220 100644 --- a/polymorphic/__init__.py +++ b/polymorphic/__init__.py @@ -10,6 +10,7 @@ Please see LICENSE and AUTHORS for more information. from polymorphic_model import PolymorphicModel from manager import PolymorphicManager from query import PolymorphicQuerySet +from query_translate import translate_polymorphic_Q_object from showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent #from showfields import ShowFieldTypes, ShowFields, ShowFieldsAndTypes # import old names for compatibility diff --git a/polymorphic/query.py b/polymorphic/query.py index 113ec90..93cf270 100644 --- a/polymorphic/query.py +++ b/polymorphic/query.py @@ -8,7 +8,8 @@ from compatibility_tools import defaultdict from django.db.models.query import QuerySet from django.contrib.contenttypes.models import ContentType -from query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args, translate_polymorphic_field_path +from query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args +from query_translate import translate_polymorphic_field_path # chunk-size: maximum number of objects requested per db-request # by the polymorphic queryset.iterator() implementation; we use the same chunk size as Django @@ -16,6 +17,7 @@ from django.db.models.query import CHUNK_SIZE # this is 100 for Dj Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE + ################################################################################### ### PolymorphicQuerySet diff --git a/polymorphic/query_translate.py b/polymorphic/query_translate.py index e094cee..ea42338 100644 --- a/polymorphic/query_translate.py +++ b/polymorphic/query_translate.py @@ -47,6 +47,27 @@ def translate_polymorphic_filter_definitions_in_kwargs(queryset_model, kwargs): return additional_args +def translate_polymorphic_Q_object(queryset_model, potential_q_object): + def tree_node_correct_field_specs(my_model, node): + " process all children of this Q node " + for i in range(len(node.children)): + child = node.children[i] + + if type(child) == tuple: + # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB ) + key, val = child + new_expr = _translate_polymorphic_filter_definition(my_model, key, val) + if new_expr: + node.children[i] = new_expr + else: + # this Q object child is another Q object, recursively process this as well + tree_node_correct_field_specs(my_model, child) + + if isinstance(potential_q_object, models.Q): + tree_node_correct_field_specs(queryset_model, potential_q_object) + + return potential_q_object + def translate_polymorphic_filter_definitions_in_args(queryset_model, args): """ Translate the non-keyword argument list for PolymorphicQuerySet.filter() @@ -60,24 +81,8 @@ def translate_polymorphic_filter_definitions_in_args(queryset_model, args): Modifies: args list """ - def tree_node_correct_field_specs(node): - " process all children of this Q node " - for i in range(len(node.children)): - child = node.children[i] - - if type(child) == tuple: - # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB ) - key, val = child - new_expr = _translate_polymorphic_filter_definition(queryset_model, key, val) - if new_expr: - node.children[i] = new_expr - else: - # this Q object child is another Q object, recursively process this as well - tree_node_correct_field_specs(child) - for q in args: - if isinstance(q, models.Q): - tree_node_correct_field_specs(q) + translate_polymorphic_Q_object(queryset_model, q) def _translate_polymorphic_filter_definition(queryset_model, field_path, field_val): diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 5dba6dc..c85e78e 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -12,7 +12,9 @@ from django.db import models from django.contrib.contenttypes.models import ContentType from pprint import pprint -from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, get_version +from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet +from polymorphic import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, get_version +from polymorphic import translate_polymorphic_Q_object class PlainA(models.Model): field1 = models.CharField(max_length=10) @@ -113,6 +115,10 @@ class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel): blog = models.ForeignKey(BlogA) text = models.CharField(max_length=10) +class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel): + blog = models.ForeignKey(BlogBase, limit_choices_to=translate_polymorphic_Q_object(BlogBase, Q(instance_of=BlogA) ) ) + text = models.CharField(max_length=10) + class ModelFieldNameTest(ShowFieldType, PolymorphicModel): modelfieldnametest = models.CharField(max_length=10) @@ -125,6 +131,7 @@ class InitTestModelSubclass(InitTestModel): def x(self): return 'XYZ' + # test bad field name #class TestBadFieldModel(ShowFieldType, PolymorphicModel): # instance_of = models.CharField(max_length=10) @@ -220,6 +227,15 @@ class testclass(TestCase): #assert False + def test_limit_choices_to(self): + "this is not really a testcase, as limit_choices_to only affects the Django admin" + # create a blog of type BlogA + blog_a = BlogA.objects.create(name='aa', info='aa') + blog_b = BlogB.objects.create(name='bb') + # create two blog entries + entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2') + entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2') + __test__ = {"doctest": """ #######################################################