Commit 91d412a578cb1ec2512686008fed03a1ffe7de50

Added tests for values_list and corrected some ordering issues in the SQLAlchemyValuesQuerySet.

The ordering of the values_list problem was being masked by the fact that the
dict in values was resolving it fine. Also implemented the flat capability
for the values_list. The implementation is not ideal but works fine. I'd
prefer not to reference flat in the clone method for SQLAlchemyValuesQuerySet
but the alternative is to duplicate the _clone in SQLAlchemyValuesListQuerySet
  
173173 that modifies the setup and iterator behavior.
174174 """
175175 from django_sqlalchemy.models.query import SQLAlchemyValuesQuerySet
176 return self._clone(klass=SQLAlchemyValuesQuerySet, setup=True, _fields=fields)
176 return self._clone(klass=SQLAlchemyValuesQuerySet, setup=True,
177 _fields=fields)
177178
178179 def values_list(self, *fields, **kwargs):
179180 """
191191 if flat and len(fields) > 1:
192192 raise TypeError("'flat' is not valid when values_list is called with more than one field.")
193193 from django_sqlalchemy.models.query import SQLAlchemyValuesListQuerySet
194 return self._clone(klass=SQLAlchemyValuesListQuerySet, setup=True, flat=flat,
195 _fields=fields)
194 return self._clone(klass=SQLAlchemyValuesListQuerySet, setup=True,
195 flat=flat, _fields=fields)
196196
197197 def dates(self, field_name, kind, order='ASC'):
198198 """
390390 c = klass(model=self.model, query=self.query._clone())
391391 c.__dict__.update(kwargs)
392392 c.field_names = self.field_names
393 c.flat = getattr(self, 'flat', None)
393394 if setup and hasattr(c, '_setup_query'):
394395 c._setup_query()
395396 return c
404404 instance.
405405 """
406406 if self._fields or self.field_names:
407 self.field_names = list(self._fields) + self.field_names
407 self.field_names = self.field_names + list(self._fields)
408408 else:
409409 # Default to all fields.
410410 self.field_names = [f.attname for f in self.model._meta.fields]
414414
415415class SQLAlchemyValuesListQuerySet(SQLAlchemyValuesQuerySet):
416416 def iterator(self):
417 if getattr(self, 'flat', None) and len(self._fields) == 1:
418 for row in iter(self.query):
417 if getattr(self, 'flat', None) and len(self.field_names) == 1:
418 for row in self.query:
419419 yield row[0]
420420 else:
421 for row in iter(self.query):
421 for row in self.query:
422422 yield row
  
1from django_sqlalchemy.test import *
2from django_sqlalchemy.backend import session
3from apps.events.models import Owner, VenueInfo, Event
4
5class TestValuesList(object):
6 def setup(self):
7 session.add_all([
8 Owner(name='Luiji Roscoe', phone='557-895-9687'),
9 Owner(name='Jeffrey Gross-Bache'),
10 Owner(name='Luiji Rosso', phone='557-895-9687')])
11
12 session.add_all([
13 VenueInfo(name='Rock and Roll Palace', address='123 Main St.', phone='408-123-4567', owner_id=Owner.query.get(1).id),
14 VenueInfo(name='The Big and Mighty', address='555 Fifth Third St.', phone='502-555-1212', owner_id=Owner.query.get(2).id),
15 VenueInfo(name='The Mighty and Big', address='545 Fifth Third St.', phone='502-505-2121', owner_id=Owner.query.get(2).id)])
16
17 v = VenueInfo.query.filter_by(name='Rock and Roll Palace').one()
18 session.add_all([
19 Event(name='Molly and the Malones', venue_info_id=v.id, body='A rocking Irish shindig.'),
20 Event(name='Johnny Bee Good', venue_info_id=v.id, body='Classic rock covers all done up in a bumblebee tuna outfit.'),
21 Event(name='JoJo Rock Show', venue_info_id=v.id, body='Fem rock, rocking you hard.')])
22
23 v = VenueInfo.query.filter_by(name='The Big and Mighty').one()
24 session.add_all([
25 Event(name='Piggy Elk and the Elkhorns', venue_info_id=v.id, body='Quintet of big band sound.'),
26 Event(name='Cello Nightly', venue_info_id=v.id, body='Smooth classics by Jim Nightly.')])
27
28 v = VenueInfo.query.filter_by(name='The Mighty and Big').one()
29 session.add_all([
30 Event(name='Johnny Come Lately', venue_info_id=v.id, body='A Kegle Performance Piece'),
31 Event(name='Headbangers Ball', venue_info_id=v.id, body='Dress up or not, but come rockin.')])
32
33 def test_should_return_values_from_table(self):
34 assert_equal([(u'Luiji Roscoe',),
35 (u'Jeffrey Gross-Bache',),
36 (u'Luiji Rosso',)], list(Owner.objects.values_list('name')))
37
38 def test_should_return_multiple_values_from_table(self):
39 assert_equal([(1, u'Luiji Roscoe',),
40 (2, u'Jeffrey Gross-Bache',),
41 (3, u'Luiji Rosso',)], list(Owner.objects.values_list('id', 'name')))
42
43 def test_should_return_all_values_if_no_value_specified(self):
44 assert_equal([(1, u'Luiji Roscoe', u'557-895-9687',),
45 (2, u'Jeffrey Gross-Bache', None,),
46 (3, u'Luiji Rosso', u'557-895-9687',)], list(Owner.objects.order_by('id').values_list()))
47
48 def test_should_maintain_order_of_specified_values(self):
49 assert_equal([(u'Luiji Roscoe', 1,),
50 (u'Jeffrey Gross-Bache', 2,),
51 (u'Luiji Rosso', 3,)], list(Owner.objects.values_list('name', 'id')))
52
53 def test_should_work_with_generative_values(self):
54 assert_equal([(u'Luiji Roscoe', 1,),
55 (u'Jeffrey Gross-Bache', 2,),
56 (u'Luiji Rosso', 3,)], list(Owner.objects.values_list('name').values_list('id')))
57
58 def test_should_return_values_of_foreign_key_item(self):
59 assert_equal([(1,),
60 (2,),
61 (2,)], list(VenueInfo.objects.values_list('owner')))
62
63 def test_should_return_only_distinct_values(self):
64 assert_equal(2, Owner.objects.values_list('phone').distinct().count())
65
66 def test_should_allow_filtering_before_and_after_values_specification(self):
67 assert_equal([(u'Luiji Roscoe',)],
68 list(Owner.objects.filter(name__startswith='L').values_list('name').filter(name__endswith='e')))
69
70 def test_should_flatten_values_list_if_specified(self):
71 assert_equal([1, 2, 3], list(VenueInfo.objects.values_list('id', flat=True).order_by('id')))