Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 14618)
+++ django/db/models/query.py	(working copy)
@@ -490,18 +490,24 @@
     # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
     ##################################################
 
-    def values(self, *fields):
-        return self._clone(klass=ValuesQuerySet, setup=True, _fields=fields)
+    def values(self, *fields, **kwargs):
+        allow_m2m = kwargs.pop('allow_m2m', False)
+        if kwargs:
+            raise TypeError('Unexpected keyword arguments to values_list: %s'
+                    % (kwargs.keys(),))
+        return self._clone(klass=ValuesQuerySet, setup=True, _fields=fields,
+                allow_m2m=allow_m2m)
 
     def values_list(self, *fields, **kwargs):
         flat = kwargs.pop('flat', False)
+        allow_m2m = kwargs.pop('allow_m2m', False)
         if kwargs:
             raise TypeError('Unexpected keyword arguments to values_list: %s'
                     % (kwargs.keys(),))
         if flat and len(fields) > 1:
             raise TypeError("'flat' is not valid when values_list is called with more than one field.")
         return self._clone(klass=ValuesListQuerySet, setup=True, flat=flat,
-                _fields=fields)
+                _fields=fields, allow_m2m=allow_m2m)
 
     def dates(self, field_name, kind, order='ASC'):
         """
@@ -870,7 +876,7 @@
         self.query.select = []
         if self.extra_names is not None:
             self.query.set_extra_mask(self.extra_names)
-        self.query.add_fields(self.field_names, False)
+        self.query.add_fields(self.field_names, self.allow_m2m)
         if self.aggregate_names is not None:
             self.query.set_aggregate_mask(self.aggregate_names)
 
@@ -886,6 +892,7 @@
         c.field_names = self.field_names
         c.extra_names = self.extra_names
         c.aggregate_names = self.aggregate_names
+        c.allow_m2m = self.allow_m2m
         if setup and hasattr(c, '_setup_query'):
             c._setup_query()
         return c
@@ -972,6 +979,7 @@
     def _clone(self, *args, **kwargs):
         clone = super(ValuesListQuerySet, self)._clone(*args, **kwargs)
         clone.flat = self.flat
+        clone.allow_m2m = self.allow_m2m
         return clone
 
 
Index: tests/modeltests/lookup/tests.py
===================================================================
--- tests/modeltests/lookup/tests.py	(revision 14618)
+++ tests/modeltests/lookup/tests.py	(working copy)
@@ -3,28 +3,43 @@
 from django.core.exceptions import FieldError
 from django.db import connection
 from django.test import TestCase, skipUnlessDBFeature
-from models import Article
+from models import Author, Article, Tag
 
 
 class LookupTests(TestCase):
 
     #def setUp(self):
     def setUp(self):
+        # Create a few Authors.
+        self.au1 = Author(name='Author 1')
+        self.au1.save()
+        self.au2 = Author(name='Author 2')
+        self.au2.save()
         # Create a couple of Articles.
-        self.a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
+        self.a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26), author=self.au1)
         self.a1.save()
-        self.a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27))
+        self.a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27), author=self.au1)
         self.a2.save()
-        self.a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27))
+        self.a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27), author=self.au1)
         self.a3.save()
-        self.a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28))
+        self.a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28), author=self.au1)
         self.a4.save()
-        self.a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0))
+        self.a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0), author=self.au2)
         self.a5.save()
-        self.a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0))
+        self.a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0), author=self.au2)
         self.a6.save()
-        self.a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27))
+        self.a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27), author=self.au2)
         self.a7.save()
+        # Create a few Tags.
+        self.t1 = Tag(name='Tag 1')
+        self.t1.save()
+        self.t1.articles.add(self.a1, self.a2, self.a3)
+        self.t2 = Tag(name='Tag 2')
+        self.t2.save()
+        self.t2.articles.add(self.a3, self.a4, self.a5)
+        self.t3 = Tag(name='Tag 3')
+        self.t3.save()
+        self.t3.articles.add(self.a5, self.a6, self.a7)
 
     def test_exists(self):
         # We can use .exists() to check that there are some
@@ -188,10 +203,50 @@
         self.assertRaises(FieldError,
             Article.objects.extra(select={'id_plus_one': 'id + 1'}).values,
             'id', 'id_plus_two')
+        # You can specify fields from related models that cross a single-valued
+        # relation (one-to-one, many-to-one).
+        self.assertQuerysetEqual(
+            Article.objects.values('headline', 'author__name'),
+            [
+                {'headline': self.a5.headline, 'author__name': self.au2.name},
+                {'headline': self.a6.headline, 'author__name': self.au2.name},
+                {'headline': self.a4.headline, 'author__name': self.au1.name},
+                {'headline': self.a2.headline, 'author__name': self.au1.name},
+                {'headline': self.a3.headline, 'author__name': self.au1.name},
+                {'headline': self.a7.headline, 'author__name': self.au2.name},
+                {'headline': self.a1.headline, 'author__name': self.au1.name},
+            ], transform=identity)
+        # If you want to specify fields from related models that cross a
+        # multi-valued relation, you need to use the allow_m2m argument.
+        self.assertQuerysetEqual(
+            Author.objects.values('name', 'article__headline', allow_m2m=True),
+            [
+                {'name': self.au1.name, 'article__headline': self.a1.headline},
+                {'name': self.au1.name, 'article__headline': self.a2.headline},
+                {'name': self.au1.name, 'article__headline': self.a3.headline},
+                {'name': self.au1.name, 'article__headline': self.a4.headline},
+                {'name': self.au2.name, 'article__headline': self.a5.headline},
+                {'name': self.au2.name, 'article__headline': self.a6.headline},
+                {'name': self.au2.name, 'article__headline': self.a7.headline},
+            ], transform=identity)
+        self.assertQuerysetEqual(
+            Author.objects.values('name', 'article__headline', 'article__tag__name', allow_m2m=True),
+            [
+                {'name': self.au1.name, 'article__headline': self.a1.headline, 'article__tag__name': self.t1.name},
+                {'name': self.au1.name, 'article__headline': self.a2.headline, 'article__tag__name': self.t1.name},
+                {'name': self.au1.name, 'article__headline': self.a3.headline, 'article__tag__name': self.t1.name},
+                {'name': self.au1.name, 'article__headline': self.a3.headline, 'article__tag__name': self.t2.name},
+                {'name': self.au1.name, 'article__headline': self.a4.headline, 'article__tag__name': self.t2.name},
+                {'name': self.au2.name, 'article__headline': self.a5.headline, 'article__tag__name': self.t2.name},
+                {'name': self.au2.name, 'article__headline': self.a5.headline, 'article__tag__name': self.t3.name},
+                {'name': self.au2.name, 'article__headline': self.a6.headline, 'article__tag__name': self.t3.name},
+                {'name': self.au2.name, 'article__headline': self.a7.headline, 'article__tag__name': self.t3.name},
+            ], transform=identity)
         # If you don't specify field names to values(), all are returned.
         self.assertQuerysetEqual(Article.objects.filter(id=self.a5.id).values(),
             [{
                 'id': self.a5.id,
+                'author_id': self.a2.id, 
                 'headline': 'Article 5',
                 'pub_date': datetime(2005, 8, 1, 9, 0)
             }], transform=identity)
@@ -402,7 +457,7 @@
             self.fail('FieldError not raised')
         except FieldError, ex:
             self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' "
-                             "into field. Choices are: headline, id, pub_date")
+                             "into field. Choices are: author, headline, id, pub_date, tag")
         try:
             Article.objects.filter(headline__starts='Article')
             self.fail('FieldError not raised')
Index: tests/modeltests/lookup/models.py
===================================================================
--- tests/modeltests/lookup/models.py	(revision 14618)
+++ tests/modeltests/lookup/models.py	(working copy)
@@ -7,11 +7,19 @@
 from django.db import models, DEFAULT_DB_ALIAS, connection
 from django.conf import settings
 
+class Author(models.Model):
+    name = models.CharField(max_length=100)
+
 class Article(models.Model):
     headline = models.CharField(max_length=100)
     pub_date = models.DateTimeField()
+    author = models.ForeignKey(Author, blank=True, null=True)
     class Meta:
         ordering = ('-pub_date', 'headline')
 
     def __unicode__(self):
         return self.headline
+
+class Tag(models.Model):
+	articles = models.ManyToManyField(Article)
+	name = models.CharField(max_length=100)
