1
0
mirror of https://github.com/django/django.git synced 2025-07-06 02:39:12 +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:
Malcolm Tredinnick 2008-02-27 00:44:44 +00:00
parent fc4c0f7b39
commit 014373b459
11 changed files with 27 additions and 20 deletions

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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

View File

@ -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())

View File

@ -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()

View File

@ -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.

View File

@ -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')

View File

@ -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
"""} """}

View File

@ -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)

View File

@ -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.