Ticket #5768: 5768-m2m-values-r14639.diff
File 5768-m2m-values-r14639.diff, 10.6 KB (added by , 14 years ago) |
---|
-
django/db/models/query.py
870 870 self.query.select = [] 871 871 if self.extra_names is not None: 872 872 self.query.set_extra_mask(self.extra_names) 873 self.query.add_fields(self.field_names, False)873 self.query.add_fields(self.field_names, True) 874 874 if self.aggregate_names is not None: 875 875 self.query.set_aggregate_mask(self.aggregate_names) 876 876 -
tests/modeltests/lookup/tests.py
3 3 from django.core.exceptions import FieldError 4 4 from django.db import connection 5 5 from django.test import TestCase, skipUnlessDBFeature 6 from models import A rticle6 from models import Author, Article, Tag 7 7 8 8 9 9 class LookupTests(TestCase): 10 10 11 11 #def setUp(self): 12 12 def setUp(self): 13 # Create a few Authors. 14 self.au1 = Author(name='Author 1') 15 self.au1.save() 16 self.au2 = Author(name='Author 2') 17 self.au2.save() 13 18 # Create a couple of Articles. 14 self.a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26) )19 self.a1 = Article(headline='Article 1', pub_date=datetime(2005, 7, 26), author=self.au1) 15 20 self.a1.save() 16 self.a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27) )21 self.a2 = Article(headline='Article 2', pub_date=datetime(2005, 7, 27), author=self.au1) 17 22 self.a2.save() 18 self.a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27) )23 self.a3 = Article(headline='Article 3', pub_date=datetime(2005, 7, 27), author=self.au1) 19 24 self.a3.save() 20 self.a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28) )25 self.a4 = Article(headline='Article 4', pub_date=datetime(2005, 7, 28), author=self.au1) 21 26 self.a4.save() 22 self.a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0) )27 self.a5 = Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0), author=self.au2) 23 28 self.a5.save() 24 self.a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0) )29 self.a6 = Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0), author=self.au2) 25 30 self.a6.save() 26 self.a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27) )31 self.a7 = Article(headline='Article 7', pub_date=datetime(2005, 7, 27), author=self.au2) 27 32 self.a7.save() 33 # Create a few Tags. 34 self.t1 = Tag(name='Tag 1') 35 self.t1.save() 36 self.t1.articles.add(self.a1, self.a2, self.a3) 37 self.t2 = Tag(name='Tag 2') 38 self.t2.save() 39 self.t2.articles.add(self.a3, self.a4, self.a5) 40 self.t3 = Tag(name='Tag 3') 41 self.t3.save() 42 self.t3.articles.add(self.a5, self.a6, self.a7) 28 43 29 44 def test_exists(self): 30 45 # We can use .exists() to check that there are some … … 182 197 'id_plus_seven': self.a1.id + 7, 183 198 'id_plus_eight': self.a1.id + 8, 184 199 }], transform=identity) 200 # You can specify fields from forward and reverse relations, just like filter(). 201 self.assertQuerysetEqual( 202 Article.objects.values('headline', 'author__name'), 203 [ 204 {'headline': self.a5.headline, 'author__name': self.au2.name}, 205 {'headline': self.a6.headline, 'author__name': self.au2.name}, 206 {'headline': self.a4.headline, 'author__name': self.au1.name}, 207 {'headline': self.a2.headline, 'author__name': self.au1.name}, 208 {'headline': self.a3.headline, 'author__name': self.au1.name}, 209 {'headline': self.a7.headline, 'author__name': self.au2.name}, 210 {'headline': self.a1.headline, 'author__name': self.au1.name}, 211 ], transform=identity) 212 self.assertQuerysetEqual( 213 Author.objects.values('name', 'article__headline').order_by('name', 'article__headline'), 214 [ 215 {'name': self.au1.name, 'article__headline': self.a1.headline}, 216 {'name': self.au1.name, 'article__headline': self.a2.headline}, 217 {'name': self.au1.name, 'article__headline': self.a3.headline}, 218 {'name': self.au1.name, 'article__headline': self.a4.headline}, 219 {'name': self.au2.name, 'article__headline': self.a5.headline}, 220 {'name': self.au2.name, 'article__headline': self.a6.headline}, 221 {'name': self.au2.name, 'article__headline': self.a7.headline}, 222 ], transform=identity) 223 self.assertQuerysetEqual( 224 Author.objects.values('name', 'article__headline', 'article__tag__name').order_by('name', 'article__headline', 'article__tag__name'), 225 [ 226 {'name': self.au1.name, 'article__headline': self.a1.headline, 'article__tag__name': self.t1.name}, 227 {'name': self.au1.name, 'article__headline': self.a2.headline, 'article__tag__name': self.t1.name}, 228 {'name': self.au1.name, 'article__headline': self.a3.headline, 'article__tag__name': self.t1.name}, 229 {'name': self.au1.name, 'article__headline': self.a3.headline, 'article__tag__name': self.t2.name}, 230 {'name': self.au1.name, 'article__headline': self.a4.headline, 'article__tag__name': self.t2.name}, 231 {'name': self.au2.name, 'article__headline': self.a5.headline, 'article__tag__name': self.t2.name}, 232 {'name': self.au2.name, 'article__headline': self.a5.headline, 'article__tag__name': self.t3.name}, 233 {'name': self.au2.name, 'article__headline': self.a6.headline, 'article__tag__name': self.t3.name}, 234 {'name': self.au2.name, 'article__headline': self.a7.headline, 'article__tag__name': self.t3.name}, 235 ], transform=identity) 185 236 # However, an exception FieldDoesNotExist will be thrown if you specify 186 237 # a non-existent field name in values() (a field that is neither in the 187 238 # model nor in extra(select)). … … 192 243 self.assertQuerysetEqual(Article.objects.filter(id=self.a5.id).values(), 193 244 [{ 194 245 'id': self.a5.id, 246 'author_id': self.au2.id, 195 247 'headline': 'Article 5', 196 248 'pub_date': datetime(2005, 8, 1, 9, 0) 197 249 }], transform=identity) … … 250 302 (self.a7.id, self.a7.id+1) 251 303 ], 252 304 transform=identity) 305 self.assertQuerysetEqual( 306 Author.objects.values_list('name', 'article__headline', 'article__tag__name').order_by('name', 'article__headline', 'article__tag__name'), 307 [ 308 (self.au1.name, self.a1.headline, self.t1.name), 309 (self.au1.name, self.a2.headline, self.t1.name), 310 (self.au1.name, self.a3.headline, self.t1.name), 311 (self.au1.name, self.a3.headline, self.t2.name), 312 (self.au1.name, self.a4.headline, self.t2.name), 313 (self.au2.name, self.a5.headline, self.t2.name), 314 (self.au2.name, self.a5.headline, self.t3.name), 315 (self.au2.name, self.a6.headline, self.t3.name), 316 (self.au2.name, self.a7.headline, self.t3.name), 317 ], transform=identity) 253 318 self.assertRaises(TypeError, Article.objects.values_list, 'id', 'headline', flat=True) 254 319 255 320 def test_get_next_previous_by(self): … … 402 467 self.fail('FieldError not raised') 403 468 except FieldError, ex: 404 469 self.assertEqual(str(ex), "Cannot resolve keyword 'pub_date_year' " 405 "into field. Choices are: headline, id, pub_date")470 "into field. Choices are: author, headline, id, pub_date, tag") 406 471 try: 407 472 Article.objects.filter(headline__starts='Article') 408 473 self.fail('FieldError not raised') -
tests/modeltests/lookup/models.py
7 7 from django.db import models, DEFAULT_DB_ALIAS, connection 8 8 from django.conf import settings 9 9 10 class Author(models.Model): 11 name = models.CharField(max_length=100) 12 class Meta: 13 ordering = ('name', ) 14 10 15 class Article(models.Model): 11 16 headline = models.CharField(max_length=100) 12 17 pub_date = models.DateTimeField() 18 author = models.ForeignKey(Author, blank=True, null=True) 13 19 class Meta: 14 20 ordering = ('-pub_date', 'headline') 15 21 16 22 def __unicode__(self): 17 23 return self.headline 24 25 class Tag(models.Model): 26 articles = models.ManyToManyField(Article) 27 name = models.CharField(max_length=100) 28 class Meta: 29 ordering = ('name', ) -
docs/ref/models/querysets.txt
400 400 401 401 A couple of subtleties that are worth mentioning: 402 402 403 * The ``values()`` method does not return anything for404 :class:`~django.db.models.ManyToManyField` attributes and will raise an405 error if you try to pass in this type of field to it.406 403 * If you have a field called ``foo`` that is a 407 404 :class:`~django.db.models.ForeignKey`, the default ``values()`` call 408 405 will return a dictionary key called ``foo_id``, since this is the name … … 453 450 but it doesn't really matter. This is your chance to really flaunt your 454 451 individualism. 455 452 453 .. versionchanged:: 1.3 454 455 The ``values()`` method previously did not return anything for 456 :class:`~django.db.models.ManyToManyField` attributes and would raise an error 457 if you tried to pass in this type of field to it. 458 459 This restriction has been lifted, and you can now also refer to fields on 460 related models with reverse relations through ``OneToOneField``, ``ForeignKey`` 461 and ``ManyToManyField`` attributes:: 462 463 Blog.objects.values('name', 'entry__headline') 464 [{'name': 'My blog', 'entry__headline': 'An entry'}, {'name': 'My blog', 'entry__headline': 'Another entry'}, ...] 465 466 Please note that when using ``values()`` in this way it is possible to trigger 467 an exponential increase in the size of your result set when used with 468 ``ManyToManyFields`` and large data sets. 469 456 470 ``values_list(*fields)`` 457 471 ~~~~~~~~~~~~~~~~~~~~~~~~ 458 472