mirror of
https://github.com/django/django.git
synced 2025-07-06 18:59:13 +00:00
queryset-refactor: Fixed #6664. Calling list() no longer swallows field errors.
This is slightly backwards incompatible with previous behaviour if you were doing Tricky Stuff(tm) -- the exception type has changed if you try to create a bad queryset. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7163 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fc4c0f7b39
commit
014373b459
@ -27,3 +27,8 @@ class MiddlewareNotUsed(Exception):
|
|||||||
class ImproperlyConfigured(Exception):
|
class ImproperlyConfigured(Exception):
|
||||||
"Django is somehow improperly configured"
|
"Django is somehow improperly configured"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class FieldError(Exception):
|
||||||
|
"""Some kind of problem with a model field."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from itertools import izip
|
|||||||
import django.db.models.manipulators
|
import django.db.models.manipulators
|
||||||
import django.db.models.manager
|
import django.db.models.manager
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
|
||||||
from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
|
from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
|
||||||
from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
|
from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
|
||||||
from django.db.models.query import delete_objects, Q
|
from django.db.models.query import delete_objects, Q
|
||||||
@ -101,7 +101,7 @@ class ModelBase(type):
|
|||||||
names = [f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]
|
names = [f.name for f in new_class._meta.local_fields + new_class._meta.many_to_many]
|
||||||
for field in base._meta.local_fields:
|
for field in base._meta.local_fields:
|
||||||
if field.name in names:
|
if field.name in names:
|
||||||
raise TypeError('Local field %r in class %r clashes with field of similar name from abstract base class %r'
|
raise FieldError('Local field %r in class %r clashes with field of similar name from abstract base class %r'
|
||||||
% (field.name, name, base.__name__))
|
% (field.name, name, base.__name__))
|
||||||
new_class.add_to_class(field.name, field)
|
new_class.add_to_class(field.name, field)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ from django.db.models.sql.where import WhereNode, EverythingNode, AND, OR
|
|||||||
from django.db.models.sql.datastructures import Count, Date
|
from django.db.models.sql.datastructures import Count, Date
|
||||||
from django.db.models.fields import FieldDoesNotExist, Field, related
|
from django.db.models.fields import FieldDoesNotExist, Field, related
|
||||||
from django.contrib.contenttypes import generic
|
from django.contrib.contenttypes import generic
|
||||||
|
from django.core.exceptions import FieldError
|
||||||
from datastructures import EmptyResultSet
|
from datastructures import EmptyResultSet
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -548,7 +549,7 @@ class Query(object):
|
|||||||
already_seen = {}
|
already_seen = {}
|
||||||
join_tuple = tuple([tuple(j) for j in joins])
|
join_tuple = tuple([tuple(j) for j in joins])
|
||||||
if join_tuple in already_seen:
|
if join_tuple in already_seen:
|
||||||
raise TypeError('Infinite loop caused by ordering.')
|
raise FieldError('Infinite loop caused by ordering.')
|
||||||
already_seen[join_tuple] = True
|
already_seen[join_tuple] = True
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
@ -735,7 +736,7 @@ class Query(object):
|
|||||||
arg, value = filter_expr
|
arg, value = filter_expr
|
||||||
parts = arg.split(LOOKUP_SEP)
|
parts = arg.split(LOOKUP_SEP)
|
||||||
if not parts:
|
if not parts:
|
||||||
raise TypeError("Cannot parse keyword query %r" % arg)
|
raise FieldError("Cannot parse keyword query %r" % arg)
|
||||||
|
|
||||||
# Work out the lookup type and remove it from 'parts', if necessary.
|
# Work out the lookup type and remove it from 'parts', if necessary.
|
||||||
if len(parts) == 1 or parts[-1] not in self.query_terms:
|
if len(parts) == 1 or parts[-1] not in self.query_terms:
|
||||||
@ -867,7 +868,7 @@ class Query(object):
|
|||||||
field, model, direct, m2m = opts.get_field_by_name(name)
|
field, model, direct, m2m = opts.get_field_by_name(name)
|
||||||
except FieldDoesNotExist:
|
except FieldDoesNotExist:
|
||||||
names = opts.get_all_field_names()
|
names = opts.get_all_field_names()
|
||||||
raise TypeError("Cannot resolve keyword %r into field. "
|
raise FieldError("Cannot resolve keyword %r into field. "
|
||||||
"Choices are: %s" % (name, ", ".join(names)))
|
"Choices are: %s" % (name, ", ".join(names)))
|
||||||
if model:
|
if model:
|
||||||
# The field lives on a base class of the current model.
|
# The field lives on a base class of the current model.
|
||||||
@ -972,7 +973,7 @@ class Query(object):
|
|||||||
joins.append([alias])
|
joins.append([alias])
|
||||||
|
|
||||||
if pos != len(names) - 1:
|
if pos != len(names) - 1:
|
||||||
raise TypeError("Join on field %r not permitted." % name)
|
raise FieldError("Join on field %r not permitted." % name)
|
||||||
|
|
||||||
return field, target, opts, joins
|
return field, target, opts, joins
|
||||||
|
|
||||||
@ -1033,7 +1034,7 @@ class Query(object):
|
|||||||
if not ORDER_PATTERN.match(item):
|
if not ORDER_PATTERN.match(item):
|
||||||
errors.append(item)
|
errors.append(item)
|
||||||
if errors:
|
if errors:
|
||||||
raise TypeError('Invalid order_by arguments: %s' % errors)
|
raise FieldError('Invalid order_by arguments: %s' % errors)
|
||||||
if ordering:
|
if ordering:
|
||||||
self.order_by.extend(ordering)
|
self.order_by.extend(ordering)
|
||||||
else:
|
else:
|
||||||
@ -1228,7 +1229,7 @@ class UpdateQuery(Query):
|
|||||||
for alias in alias_list:
|
for alias in alias_list:
|
||||||
if self.alias_map[alias][ALIAS_REFCOUNT]:
|
if self.alias_map[alias][ALIAS_REFCOUNT]:
|
||||||
if table:
|
if table:
|
||||||
raise TypeError('Updates can only access a single database table at a time.')
|
raise FieldError('Updates can only access a single database table at a time.')
|
||||||
table = alias
|
table = alias
|
||||||
else:
|
else:
|
||||||
table = self.tables[0]
|
table = self.tables[0]
|
||||||
@ -1271,7 +1272,7 @@ class UpdateQuery(Query):
|
|||||||
field, model, direct, m2m = self.model._meta.get_field_by_name(name)
|
field, model, direct, m2m = self.model._meta.get_field_by_name(name)
|
||||||
if not direct or m2m:
|
if not direct or m2m:
|
||||||
# Can only update non-relation fields and foreign keys.
|
# Can only update non-relation fields and foreign keys.
|
||||||
raise TypeError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field)
|
raise fieldError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field)
|
||||||
if field.rel and isinstance(val, Model):
|
if field.rel and isinstance(val, Model):
|
||||||
val = val.pk
|
val = val.pk
|
||||||
self.values.append((field.column, val))
|
self.values.append((field.column, val))
|
||||||
|
@ -71,7 +71,7 @@ __test__ = {'API_TESTS':"""
|
|||||||
>>> Author.objects.filter(firstname__exact='John')
|
>>> Author.objects.filter(firstname__exact='John')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'firstname' into field. Choices are: article, first_name, id, last_name
|
FieldError: Cannot resolve keyword 'firstname' into field. Choices are: article, first_name, id, last_name
|
||||||
|
|
||||||
>>> a = Author.objects.get(last_name__exact='Smith')
|
>>> a = Author.objects.get(last_name__exact='Smith')
|
||||||
>>> a.first_name
|
>>> a.first_name
|
||||||
|
@ -5,6 +5,7 @@ Tests for field subclassing.
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
|
from django.core.exceptions import FieldError
|
||||||
|
|
||||||
class Small(object):
|
class Small(object):
|
||||||
"""
|
"""
|
||||||
@ -50,7 +51,7 @@ class SmallField(models.Field):
|
|||||||
return [force_unicode(v) for v in value]
|
return [force_unicode(v) for v in value]
|
||||||
if lookup_type == 'isnull':
|
if lookup_type == 'isnull':
|
||||||
return []
|
return []
|
||||||
raise TypeError('Invalid lookup type: %r' % lookup_type)
|
raise FieldError('Invalid lookup type: %r' % lookup_type)
|
||||||
|
|
||||||
def flatten_data(self, follow, obj=None):
|
def flatten_data(self, follow, obj=None):
|
||||||
return {self.attname: force_unicode(self._get_val_from_obj(obj))}
|
return {self.attname: force_unicode(self._get_val_from_obj(obj))}
|
||||||
@ -94,7 +95,7 @@ True
|
|||||||
>>> MyModel.objects.filter(data__lt=s)
|
>>> MyModel.objects.filter(data__lt=s)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Invalid lookup type: 'lt'
|
FieldError: Invalid lookup type: 'lt'
|
||||||
|
|
||||||
# Serialization works, too.
|
# Serialization works, too.
|
||||||
>>> stream = serializers.serialize("json", MyModel.objects.all())
|
>>> stream = serializers.serialize("json", MyModel.objects.all())
|
||||||
|
@ -270,12 +270,12 @@ DoesNotExist: Article matching query does not exist.
|
|||||||
>>> Article.objects.filter(pub_date_year='2005').count()
|
>>> Article.objects.filter(pub_date_year='2005').count()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'pub_date_year' into field. Choices are: headline, id, pub_date
|
FieldError: Cannot resolve keyword 'pub_date_year' into field. Choices are: headline, id, pub_date
|
||||||
|
|
||||||
>>> Article.objects.filter(headline__starts='Article')
|
>>> Article.objects.filter(headline__starts='Article')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Join on field 'headline' not permitted.
|
FieldError: Join on field 'headline' not permitted.
|
||||||
|
|
||||||
# Create some articles with a bit more interesting headlines for testing field lookups:
|
# Create some articles with a bit more interesting headlines for testing field lookups:
|
||||||
>>> now = datetime.now()
|
>>> now = datetime.now()
|
||||||
|
@ -179,13 +179,13 @@ False
|
|||||||
>>> Article.objects.filter(reporter_id__exact=1)
|
>>> Article.objects.filter(reporter_id__exact=1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
|
FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
|
||||||
|
|
||||||
# You need to specify a comparison clause
|
# You need to specify a comparison clause
|
||||||
>>> Article.objects.filter(reporter_id=1)
|
>>> Article.objects.filter(reporter_id=1)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
|
FieldError: Cannot resolve keyword 'reporter_id' into field. Choices are: headline, id, pub_date, reporter
|
||||||
|
|
||||||
# You can also instantiate an Article by passing
|
# You can also instantiate an Article by passing
|
||||||
# the Reporter's ID instead of a Reporter object.
|
# the Reporter's ID instead of a Reporter object.
|
||||||
|
@ -148,7 +148,7 @@ Test constructor for Restaurant.
|
|||||||
>>> Restaurant.objects.filter(supplier__name='foo')
|
>>> Restaurant.objects.filter(supplier__name='foo')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'supplier' into field. Choices are: address, id, italianrestaurant, lot, name, place_ptr, provider, rating, serves_hot_dogs, serves_pizza
|
FieldError: Cannot resolve keyword 'supplier' into field. Choices are: address, id, italianrestaurant, lot, name, place_ptr, provider, rating, serves_hot_dogs, serves_pizza
|
||||||
|
|
||||||
# Parent fields can be used directly in filters on the child model.
|
# Parent fields can be used directly in filters on the child model.
|
||||||
>>> Restaurant.objects.filter(name='Demon Dogs')
|
>>> Restaurant.objects.filter(name='Demon Dogs')
|
||||||
|
@ -55,5 +55,5 @@ __test__ = {'API_TESTS':"""
|
|||||||
>>> Poll.objects.get(choice__name__exact="This is the answer")
|
>>> Poll.objects.get(choice__name__exact="This is the answer")
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'choice' into field. Choices are: creator, id, poll_choice, question, related_choice
|
FieldError: Cannot resolve keyword 'choice' into field. Choices are: creator, id, poll_choice, question, related_choice
|
||||||
"""}
|
"""}
|
||||||
|
@ -37,7 +37,7 @@ Excluding the previous result returns everything.
|
|||||||
>>> Choice.objects.filter(foo__exact=None)
|
>>> Choice.objects.filter(foo__exact=None)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Cannot resolve keyword 'foo' into field. Choices are: choice, id, poll
|
FieldError: Cannot resolve keyword 'foo' into field. Choices are: choice, id, poll
|
||||||
|
|
||||||
# Can't use None on anything other than __exact
|
# Can't use None on anything other than __exact
|
||||||
>>> Choice.objects.filter(id__gt=None)
|
>>> Choice.objects.filter(id__gt=None)
|
||||||
|
@ -394,7 +394,7 @@ Bug #2076
|
|||||||
>>> LoopX.objects.all()
|
>>> LoopX.objects.all()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
TypeError: Infinite loop caused by ordering.
|
FieldError: Infinite loop caused by ordering.
|
||||||
|
|
||||||
# If the remote model does not have a default ordering, we order by its 'id'
|
# If the remote model does not have a default ordering, we order by its 'id'
|
||||||
# field.
|
# field.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user