Allow for matches against unsaved objects in querysets (which will therefore

match nothing). This allows for some more straightforward code in the admin
interface.

Fixed #7488 (all the debugging there was done by Brian Rosner, who narrowed it
down to the item in this patch).


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8061 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-07-23 06:12:15 +00:00
parent 3912403550
commit a7b556ca04
2 changed files with 40 additions and 9 deletions

View File

@ -35,20 +35,30 @@ class WhereNode(tree.Node):
storing any reference to field objects). Otherwise, the 'data' is storing any reference to field objects). Otherwise, the 'data' is
stored unchanged and can be anything with an 'as_sql()' method. stored unchanged and can be anything with an 'as_sql()' method.
""" """
# Because of circular imports, we need to import this here.
from django.db.models.base import ObjectDoesNotExist
if not isinstance(data, (list, tuple)): if not isinstance(data, (list, tuple)):
super(WhereNode, self).add(data, connector) super(WhereNode, self).add(data, connector)
return return
alias, col, field, lookup_type, value = data alias, col, field, lookup_type, value = data
try:
if field: if field:
params = field.get_db_prep_lookup(lookup_type, value) params = field.get_db_prep_lookup(lookup_type, value)
db_type = field.db_type() db_type = field.db_type()
else: else:
# This is possible when we add a comparison to NULL sometimes (we # This is possible when we add a comparison to NULL sometimes
# don't really need to waste time looking up the associated field # (we don't really need to waste time looking up the associated
# object). # field object).
params = Field().get_db_prep_lookup(lookup_type, value) params = Field().get_db_prep_lookup(lookup_type, value)
db_type = None db_type = None
except ObjectDoesNotExist:
# This can happen when trying to insert a reference to a null pk.
# We break out of the normal path and indicate there's nothing to
# match.
super(WhereNode, self).add(NothingNode(), connector)
return
if isinstance(value, datetime.datetime): if isinstance(value, datetime.datetime):
annotation = datetime.datetime annotation = datetime.datetime
else: else:
@ -190,3 +200,14 @@ class EverythingNode(object):
def relabel_aliases(self, change_map, node=None): def relabel_aliases(self, change_map, node=None):
return return
class NothingNode(object):
"""
A node that matches nothing.
"""
def as_sql(self, qn=None):
raise EmptyResultSet
def relabel_aliases(self, change_map, node=None):
return

View File

@ -43,12 +43,17 @@ class ParkingLot(Place):
def __unicode__(self): def __unicode__(self):
return u"%s the parking lot" % self.name return u"%s the parking lot" % self.name
class Supplier(models.Model):
restaurant = models.ForeignKey(Restaurant)
class Parent(models.Model): class Parent(models.Model):
created = models.DateTimeField(default=datetime.datetime.now) created = models.DateTimeField(default=datetime.datetime.now)
class Child(Parent): class Child(Parent):
name = models.CharField(max_length=10) name = models.CharField(max_length=10)
__test__ = {'API_TESTS':""" __test__ = {'API_TESTS':"""
# Regression for #7350, #7202 # Regression for #7350, #7202
# Check that when you create a Parent object with a specific reference to an # Check that when you create a Parent object with a specific reference to an
@ -172,4 +177,9 @@ True
>>> r.id == r.place_ptr_id >>> r.id == r.place_ptr_id
True True
# Regression test for #7488. This looks a little crazy, but it's the equivalent
# of what the admin interface has to do for the edit-inline case.
>>> Supplier.objects.filter(restaurant=Restaurant(name='xx', address='yy'))
[]
"""} """}