Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

queryset-refactor: Made the use of values() for ForeignKey fields con…

…sistent

and documented this feature. Refs #4358.


git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6516 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 70d5e32e13426372d3d98bb7664d8a69975ed885 1 parent 4c4341f
@malcolmt malcolmt authored
View
15 django/db/models/query.py
@@ -391,17 +391,22 @@ def _setup_query(self):
# 'fields' is used to configure the query, whilst field_names is stored
# in this object for use by iterator().
if self._fields:
+ opts = self.model._meta
+ all = dict([(field.column, field) for field in opts.fields])
+ all.update([(field.name, field) for field in opts.fields])
if not self.query.extra_select:
- fields = [self.model._meta.get_field(f, many_to_many=False)
- for f in self._fields]
+ try:
+ fields = [all[f] for f in self._fields]
+ except KeyError, e:
+ raise FieldDoesNotExist('%s has no field named %r'
+ % (opts.object_name, e.args[0]))
field_names = self._fields
else:
fields = []
field_names = []
for f in self._fields:
- if f in [field.name for field in self.model._meta.fields]:
- fields.append(self.model._meta.get_field(f,
- many_to_many=False))
+ if f in all:
+ fields.append(all[f])
field_names.append(f)
elif not self.query.extra_select.has_key(f):
raise FieldDoesNotExist('%s has no field named %r'
View
24 docs/db-api.txt
@@ -583,6 +583,30 @@ Example::
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
+A couple of subtleties that are worth mentioning:
+
+ * The ``values()`` method does not return anything for ``ManyToManyField``
+ attributes and will raise an error if you try to pass in this type of
+ field to it.
+ * If you have a field called ``foo`` that is a ``ForeignKey``, the default
+ ``values()`` call will return a dictionary key called ``foo_id``, since
+ this is the name of the hidden model attribute that stores the actual
+ value (the ``foo`` attribute refers to the related model). When you are
+ calling ``values()`` and passing in field names, you can pass in either
+ ``foo`` or ``foo_id`` and you will get back the same thing (the
+ dictionary key will match the field name you passed in).
+
+ For example::
+
+ >>> Entry.objects.values()
+ [{'blog_id: 1, 'headline': u'First Entry', ...}, ...]
+
+ >>> Entry.objects.values('blog')
+ [{'blog': 1}, ...]
+
+ >>> Entry.objects.values('blog_id')
+ [{'blog_id': 1}, ...]
+
A ``ValuesQuerySet`` is useful when you know you're only going to need values
from a small number of the available fields and you won't need the
functionality of a model instance object. It's more efficient to select only
View
19 tests/regressiontests/queries/models.py
@@ -334,5 +334,24 @@ def __unicode__(self):
Bug #5321
>>> Note.objects.values('misc').distinct().order_by('note', '-misc')
[{'misc': u'foo'}, {'misc': u'bar'}]
+
+Bug #4358
+If you don't pass any fields to values(), relation fields are returned as
+"foo_id" keys, not "foo". For consistency, you should be able to pass "foo_id"
+in the fields list and have it work, too. We actually allow both "foo" and
+"foo_id".
+
+# The *_id version is returned by default.
+>>> 'note_id' in ExtraInfo.objects.values()[0]
+True
+
+# You can also pass it in explicitly.
+>>> ExtraInfo.objects.values('note_id')
+[{'note_id': 1}, {'note_id': 2}]
+
+# ...or use the field name.
+>>> ExtraInfo.objects.values('note')
+[{'note': 1}, {'note': 2}]
+
"""}
Please sign in to comment.
Something went wrong with that request. Please try again.