Fixed #1579 - added support for 'Q' objects in limit_choices_to.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@2850 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2006-05-06 00:26:24 +00:00
parent 3f932e31dc
commit f57e34e990
8 changed files with 39 additions and 8 deletions

View File

@ -714,7 +714,7 @@ class ChangeList(object):
qs = qs & other_qs
if self.opts.one_to_one_field:
qs = qs.filter(**self.opts.one_to_one_field.rel.limit_choices_to)
qs = qs.complex_filter(self.opts.one_to_one_field.rel.limit_choices_to)
return qs

View File

@ -295,7 +295,7 @@ class Field(object):
return first_choice + list(self.choices)
rel_model = self.rel.to
return first_choice + [(x._get_pk_val(), str(x))
for x in rel_model._default_manager.filter(**self.rel.limit_choices_to)]
for x in rel_model._default_manager.complex_filter(self.rel.limit_choices_to)]
def get_choices_default(self):
if self.radio_admin:

View File

@ -679,7 +679,9 @@ class ManyToOneRel:
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin
self.num_extra_on_change, self.related_name = num_extra_on_change, related_name
self.limit_choices_to = limit_choices_to or {}
if limit_choices_to is None:
limit_choices_to = {}
self.limit_choices_to = limit_choices_to
self.lookup_overrides = lookup_overrides or {}
self.raw_id_admin = raw_id_admin
self.multiple = True
@ -695,7 +697,9 @@ class OneToOneRel(ManyToOneRel):
self.to, self.field_name = to, field_name
self.num_in_admin, self.edit_inline = num_in_admin, edit_inline
self.related_name = related_name
self.limit_choices_to = limit_choices_to or {}
if limit_choices_to is None:
limit_choices_to = {}
self.limit_choices_to = limit_choices_to
self.lookup_overrides = lookup_overrides or {}
self.raw_id_admin = raw_id_admin
self.multiple = False
@ -707,7 +711,9 @@ class ManyToManyRel:
self.num_in_admin = num_in_admin
self.related_name = related_name
self.filter_interface = filter_interface
self.limit_choices_to = limit_choices_to or {}
if limit_choices_to is None:
limit_choices_to = {}
self.limit_choices_to = limit_choices_to
self.edit_inline = False
self.raw_id_admin = raw_id_admin
self.symmetrical = symmetrical

View File

@ -68,6 +68,9 @@ class Manager(object):
def filter(self, *args, **kwargs):
return self.get_query_set().filter(*args, **kwargs)
def complex_filter(self, *args, **kwargs):
return self.get_query_set().complex_filter(*args, **kwargs)
def exclude(self, *args, **kwargs):
return self.get_query_set().exclude(*args, **kwargs)

View File

@ -261,9 +261,9 @@ class AutomaticChangeManipulator(AutomaticManipulator):
# Sanity check -- Make sure the "parent" object exists.
# For example, make sure the Place exists for the Restaurant.
# Let the ObjectDoesNotExist exception propagate up.
lookup_kwargs = self.opts.one_to_one_field.rel.limit_choices_to
lookup_kwargs['%s__exact' % self.opts.one_to_one_field.rel.field_name] = obj_key
self.opts.one_to_one_field.rel.to.get_model_module().get(**lookup_kwargs)
limit_choices_to = self.opts.one_to_one_field.rel.limit_choices_to
lookup_kwargs = {'%s__exact' % self.opts.one_to_one_field.rel.field_name: obj_key}
self.opts.one_to_one_field.rel.to.get_model_module().complex_filter(limit_choices_to).get(**lookup_kwargs)
params = dict([(f.attname, f.get_default()) for f in self.opts.fields])
params[self.opts.pk.attname] = obj_key
self.original_object = self.opts.get_model_module().Klass(**params)

View File

@ -297,6 +297,17 @@ class QuerySet(object):
clone._filters = clone._filters & reduce(operator.and_, args)
return clone
def complex_filter(self, filter_obj):
"""Returns a new QuerySet instance with filter_obj added to the filters.
filter_obj can be a Q object (has 'get_sql' method) or a dictionary of
keyword lookup arguments."""
# This exists to support framework features such as 'limit_choices_to',
# and usually it will be more natural to use other methods.
if hasattr(filter_obj, 'get_sql'):
return self._filter_or_exclude(None, filter_obj)
else:
return self._filter_or_exclude(Q, **filter_obj)
def select_related(self, true_or_false=True):
"Returns a new QuerySet instance with '_select_related' modified."
return self._clone(_select_related=true_or_false)

View File

@ -704,6 +704,10 @@ relationship should work. All are optional:
``pub_date`` before the current date/time to be
chosen.
Instead of a dictionary this can also be a ``Q`` object
(an object with a ``get_sql()`` method) for more complex
queries.
Not compatible with ``edit_inline``.
``max_num_in_admin`` For inline-edited objects, this is the maximum

View File

@ -86,4 +86,11 @@ Hello and goodbye
>>> Article.objects.filter(Q(headline__startswith='Hello')).in_bulk([1,2])
{1: Hello}
# The 'complex_filter' method supports framework features such as
# 'limit_choices_to' which normally take a single dictionary of lookup arguments
# but need to support arbitrary queries via Q objects too.
>>> Article.objects.complex_filter({'pk': 1})
[Hello]
>>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2))
[Hello, Goodbye]
"""