parts/django/tests/regressiontests/extra_regress/tests.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 from django.test import TestCase
       
     2 
       
     3 from django.utils.datastructures import SortedDict
       
     4 
       
     5 from django.contrib.auth.models import User
       
     6 from regressiontests.extra_regress.models import TestObject, Order, \
       
     7         RevisionableModel
       
     8 
       
     9 import datetime
       
    10 
       
    11 class ExtraRegressTests(TestCase):
       
    12 
       
    13     def setUp(self):
       
    14         self.u = User.objects.create_user(
       
    15                     username="fred",
       
    16                     password="secret",
       
    17                     email="fred@example.com"
       
    18         )
       
    19 
       
    20     def test_regression_7314_7372(self):
       
    21         """
       
    22         Regression tests for #7314 and #7372
       
    23         """
       
    24         rm = RevisionableModel.objects.create(
       
    25             title='First Revision',
       
    26             when=datetime.datetime(2008, 9, 28, 10, 30, 0)
       
    27         )
       
    28         self.assertEqual(rm.pk, rm.base.pk)
       
    29 
       
    30         rm2 = rm.new_revision()
       
    31         rm2.title = "Second Revision"
       
    32         rm.when = datetime.datetime(2008, 9, 28, 14, 25, 0)
       
    33         rm2.save()
       
    34 
       
    35         self.assertEqual(rm2.title, 'Second Revision')
       
    36         self.assertEqual(rm2.base.title, 'First Revision')
       
    37 
       
    38         self.assertNotEqual(rm2.pk, rm.pk)
       
    39         self.assertEqual(rm2.base.pk, rm.pk)
       
    40 
       
    41         # Queryset to match most recent revision:
       
    42         qs = RevisionableModel.objects.extra(
       
    43                 where=["%(table)s.id IN (SELECT MAX(rev.id) FROM %(table)s rev GROUP BY rev.base_id)" % {
       
    44                     'table': RevisionableModel._meta.db_table,
       
    45                 }]
       
    46         )
       
    47 
       
    48         self.assertQuerysetEqual(qs,
       
    49             [('Second Revision', 'First Revision')],
       
    50             transform=lambda r: (r.title, r.base.title)
       
    51         )
       
    52 
       
    53         # Queryset to search for string in title:
       
    54         qs2 = RevisionableModel.objects.filter(title__contains="Revision")
       
    55         self.assertQuerysetEqual(qs2,
       
    56             [
       
    57                 ('First Revision', 'First Revision'),
       
    58                 ('Second Revision', 'First Revision'),
       
    59             ],
       
    60             transform=lambda r: (r.title, r.base.title)
       
    61         )
       
    62 
       
    63         # Following queryset should return the most recent revision:
       
    64         self.assertQuerysetEqual(qs & qs2,
       
    65             [('Second Revision', 'First Revision')],
       
    66             transform=lambda r: (r.title, r.base.title)
       
    67         )
       
    68 
       
    69     def test_extra_stay_tied(self):
       
    70         # Extra select parameters should stay tied to their corresponding
       
    71         # select portions. Applies when portions are updated or otherwise
       
    72         # moved around.
       
    73         qs = User.objects.extra(
       
    74                     select=SortedDict((("alpha", "%s"), ("beta", "2"),  ("gamma", "%s"))),
       
    75                     select_params=(1, 3)
       
    76         )
       
    77         qs = qs.extra(select={"beta": 4})
       
    78         qs = qs.extra(select={"alpha": "%s"}, select_params=[5])
       
    79         self.assertEqual(
       
    80             list(qs.filter(id=self.u.id).values('alpha', 'beta', 'gamma')),
       
    81             [{'alpha': 5, 'beta': 4, 'gamma': 3}]
       
    82         )
       
    83 
       
    84     def test_regression_7957(self):
       
    85         """
       
    86         Regression test for #7957: Combining extra() calls should leave the
       
    87         corresponding parameters associated with the right extra() bit. I.e.
       
    88         internal dictionary must remain sorted.
       
    89         """
       
    90         self.assertEqual(
       
    91             User.objects.extra(select={"alpha": "%s"}, select_params=(1,)
       
    92                        ).extra(select={"beta": "%s"}, select_params=(2,))[0].alpha,
       
    93             1)
       
    94 
       
    95         self.assertEqual(
       
    96             User.objects.extra(select={"beta": "%s"}, select_params=(1,)
       
    97                        ).extra(select={"alpha": "%s"}, select_params=(2,))[0].alpha,
       
    98             2)
       
    99 
       
   100     def test_regression_7961(self):
       
   101         """
       
   102         Regression test for #7961: When not using a portion of an
       
   103         extra(...) in a query, remove any corresponding parameters from the
       
   104         query as well.
       
   105         """
       
   106         self.assertEqual(
       
   107             list(User.objects.extra(select={"alpha": "%s"}, select_params=(-6,)
       
   108                     ).filter(id=self.u.id).values_list('id', flat=True)),
       
   109             [self.u.id]
       
   110         )
       
   111 
       
   112     def test_regression_8063(self):
       
   113         """
       
   114         Regression test for #8063: limiting a query shouldn't discard any
       
   115         extra() bits.
       
   116         """
       
   117         qs = User.objects.all().extra(where=['id=%s'], params=[self.u.id])
       
   118         self.assertQuerysetEqual(qs, ['<User: fred>'])
       
   119         self.assertQuerysetEqual(qs[:1], ['<User: fred>'])
       
   120 
       
   121     def test_regression_8039(self):
       
   122         """
       
   123         Regression test for #8039: Ordering sometimes removed relevant tables
       
   124         from extra(). This test is the critical case: ordering uses a table,
       
   125         but then removes the reference because of an optimisation. The table
       
   126         should still be present because of the extra() call.
       
   127         """
       
   128         self.assertQuerysetEqual(
       
   129                 Order.objects.extra(where=["username=%s"],
       
   130                                     params=["fred"],
       
   131                                     tables=["auth_user"]
       
   132                             ).order_by('created_by'),
       
   133                 []
       
   134         )
       
   135 
       
   136     def test_regression_8819(self):
       
   137         """
       
   138         Regression test for #8819: Fields in the extra(select=...) list
       
   139         should be available to extra(order_by=...).
       
   140         """
       
   141         self.assertQuerysetEqual(
       
   142             User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}).distinct(),
       
   143             ['<User: fred>']
       
   144         )
       
   145         self.assertQuerysetEqual(
       
   146             User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']),
       
   147             ['<User: fred>']
       
   148         )
       
   149         self.assertQuerysetEqual(
       
   150             User.objects.filter(pk=self.u.id).extra(select={'extra_field': 1}, order_by=['extra_field']).distinct(),
       
   151             ['<User: fred>']
       
   152         )
       
   153 
       
   154     def test_dates_query(self):
       
   155         """
       
   156         When calling the dates() method on a queryset with extra selection
       
   157         columns, we can (and should) ignore those columns. They don't change
       
   158         the result and cause incorrect SQL to be produced otherwise.
       
   159         """
       
   160         rm = RevisionableModel.objects.create(
       
   161             title='First Revision',
       
   162             when=datetime.datetime(2008, 9, 28, 10, 30, 0)
       
   163         )
       
   164 
       
   165         self.assertQuerysetEqual(
       
   166             RevisionableModel.objects.extra(select={"the_answer": 'id'}).dates('when', 'month'),
       
   167             ['datetime.datetime(2008, 9, 1, 0, 0)']
       
   168         )
       
   169 
       
   170     def test_values_with_extra(self):
       
   171         """
       
   172         Regression test for #10256... If there is a values() clause, Extra
       
   173         columns are only returned if they are explicitly mentioned.
       
   174         """
       
   175         obj = TestObject(first='first', second='second', third='third')
       
   176         obj.save()
       
   177 
       
   178         self.assertEqual(
       
   179             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values()),
       
   180             [{'bar': u'second', 'third': u'third', 'second': u'second', 'whiz': u'third', 'foo': u'first', 'id': obj.pk, 'first': u'first'}]
       
   181         )
       
   182 
       
   183         # Extra clauses after an empty values clause are still included
       
   184         self.assertEqual(
       
   185             list(TestObject.objects.values().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
       
   186             [{'bar': u'second', 'third': u'third', 'second': u'second', 'whiz': u'third', 'foo': u'first', 'id': obj.pk, 'first': u'first'}]
       
   187         )
       
   188 
       
   189         # Extra columns are ignored if not mentioned in the values() clause
       
   190         self.assertEqual(
       
   191             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second')),
       
   192             [{'second': u'second', 'first': u'first'}]
       
   193         )
       
   194 
       
   195         # Extra columns after a non-empty values() clause are ignored
       
   196         self.assertEqual(
       
   197             list(TestObject.objects.values('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
       
   198             [{'second': u'second', 'first': u'first'}]
       
   199         )
       
   200 
       
   201         # Extra columns can be partially returned
       
   202         self.assertEqual(
       
   203             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('first', 'second', 'foo')),
       
   204             [{'second': u'second', 'foo': u'first', 'first': u'first'}]
       
   205         )
       
   206 
       
   207         # Also works if only extra columns are included
       
   208         self.assertEqual(
       
   209             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values('foo', 'whiz')),
       
   210             [{'foo': u'first', 'whiz': u'third'}]
       
   211         )
       
   212 
       
   213         # Values list works the same way
       
   214         # All columns are returned for an empty values_list()
       
   215         self.assertEqual(
       
   216             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list()),
       
   217             [(u'first', u'second', u'third', obj.pk, u'first', u'second', u'third')]
       
   218         )
       
   219 
       
   220         # Extra columns after an empty values_list() are still included
       
   221         self.assertEqual(
       
   222             list(TestObject.objects.values_list().extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
       
   223             [(u'first', u'second', u'third', obj.pk, u'first', u'second', u'third')]
       
   224         )
       
   225 
       
   226         # Extra columns ignored completely if not mentioned in values_list()
       
   227         self.assertEqual(
       
   228             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second')),
       
   229             [(u'first', u'second')]
       
   230         )
       
   231 
       
   232         # Extra columns after a non-empty values_list() clause are ignored completely
       
   233         self.assertEqual(
       
   234             list(TestObject.objects.values_list('first', 'second').extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third'))))),
       
   235             [(u'first', u'second')]
       
   236         )
       
   237 
       
   238         self.assertEqual(
       
   239             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('second', flat=True)),
       
   240             [u'second']
       
   241         )
       
   242 
       
   243         # Only the extra columns specified in the values_list() are returned
       
   244         self.assertEqual(
       
   245             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first', 'second', 'whiz')),
       
   246             [(u'first', u'second', u'third')]
       
   247         )
       
   248 
       
   249         # ...also works if only extra columns are included
       
   250         self.assertEqual(
       
   251             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('foo','whiz')),
       
   252             [(u'first', u'third')]
       
   253         )
       
   254 
       
   255         self.assertEqual(
       
   256             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', flat=True)),
       
   257             [u'third']
       
   258         )
       
   259 
       
   260         # ... and values are returned in the order they are specified
       
   261         self.assertEqual(
       
   262             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz','foo')),
       
   263             [(u'third', u'first')]
       
   264         )
       
   265 
       
   266         self.assertEqual(
       
   267             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('first','id')),
       
   268             [(u'first', obj.pk)]
       
   269         )
       
   270 
       
   271         self.assertEqual(
       
   272             list(TestObject.objects.extra(select=SortedDict((('foo','first'), ('bar','second'), ('whiz','third')))).values_list('whiz', 'first', 'bar', 'id')),
       
   273             [(u'third', u'first', u'second', obj.pk)]
       
   274         )
       
   275 
       
   276     def test_regression_10847(self):
       
   277         """
       
   278         Regression for #10847: the list of extra columns can always be
       
   279         accurately evaluated. Using an inner query ensures that as_sql() is
       
   280         producing correct output without requiring full evaluation and
       
   281         execution of the inner query.
       
   282         """
       
   283         obj = TestObject(first='first', second='second', third='third')
       
   284         obj.save()
       
   285 
       
   286         self.assertEqual(
       
   287             list(TestObject.objects.extra(select={'extra': 1}).values('pk')),
       
   288             [{'pk': obj.pk}]
       
   289         )
       
   290 
       
   291         self.assertQuerysetEqual(
       
   292             TestObject.objects.filter(
       
   293                     pk__in=TestObject.objects.extra(select={'extra': 1}).values('pk')
       
   294             ),
       
   295             ['<TestObject: TestObject: first,second,third>']
       
   296         )
       
   297 
       
   298         self.assertEqual(
       
   299             list(TestObject.objects.values('pk').extra(select={'extra': 1})),
       
   300             [{'pk': obj.pk}]
       
   301         )
       
   302 
       
   303         self.assertQuerysetEqual(
       
   304             TestObject.objects.filter(
       
   305                  pk__in=TestObject.objects.values('pk').extra(select={'extra': 1})
       
   306             ),
       
   307             ['<TestObject: TestObject: first,second,third>']
       
   308         )
       
   309 
       
   310         self.assertQuerysetEqual(
       
   311             TestObject.objects.filter(pk=obj.pk) |
       
   312                TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
       
   313             ['<TestObject: TestObject: first,second,third>']
       
   314         )