Changeset 3744

Show
Ignore:
Timestamp:
11/20/07 21:35:43 (8 months ago)
Author:
roger
Message:

Fix #1618:

  • paginate's default_reversed is deprecated with a warning.
  • paginate's default_order can handle a string or a list of strings, where every string started with a dash indicates a reverse ordering.
  • refactoring of tests (and + tests covering this feature)

Thanks to Joel Pearson for bringing this nice idea to ML.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.0/CHANGELOG.txt

    r3742 r3744  
    551.0.4: 
    66---------------------------- 
     7 
     8Deprecations 
     9~~~~~~~~~~~~ 
     10 
     11* Paginate ``default_order`` has been greatly improved. Use of the  
     12  ``default_reversed`` parameter has been deprecated. It will still be used 
     13  if it is informed, but a DeprecationWarning will be displayed. 
    714 
    815Changes 
     
    3239  should raise a redirect when current page is out of bound and the 
    3340  last page is requested, respectively. 
     41* Paginate ``default_order`` can now be a string or a list of strings. 
     42  The list of string is used to specify the ordering of multiple columns. 
     43  Every string starting with a dash (``-``) indicates that the column will  
     44  have its default ordering reversed (#1618). 
    3445 
    3546Fixes 
  • branches/1.0/turbogears/paginate.py

    r3735 r3744  
    33from math import ceil 
    44import logging 
     5import warnings 
    56 
    67import cherrypy 
     
    4142_simulate_offset = None 
    4243 
    43 def paginate(var_name, default_order='', default_reversed=False, limit=10, 
     44def paginate(var_name, default_order='', default_reversed=None, limit=10, 
    4445            allow_limit_override=False, max_pages=5, dynamic_limit=None): 
    4546    ''' 
     
    5152 
    5253    @param default_order: Needs work! XXX 
    53     @type default_order: string 
     54    @type default_order: string or a list of strings. Any string starting with 
     55    "-" (dash) indicates a reverse order for that field/column. 
    5456 
    5557    @param default_reversed: Needs work! XXX 
    56     @type default_reversed: Boolean 
     58    @type default_reversed: Boolean [Deprecated] 
    5759 
    5860    @param limit: the hard coded limit that the paginate decorator will 
     
    8890                return default 
    8991 
     92            if default_reversed is not None: 
     93                warnings.warn( 
     94                    "default_reversed is deprecated. Use default_order='-field'" 
     95                    " to indicate default reversed order or" 
     96                    " default_order=['field1', '-field2, 'field3']" 
     97                    " for multiple fields", DeprecationWarning, 2) 
     98 
    9099            get = turbogears.config.get 
    91100 
     
    144153 
    145154            elif default_order and not ordering: 
    146                 ordering = {default_order:[0, not default_reversed]} 
     155                if isinstance(default_order, basestring): 
     156                    # adapt old style to new style 
     157                    df = [(default_reversed and "-" or "") + default_order] 
     158                elif default_reversed: 
     159                    raise StandardError("default_reversed (deprecated) is only " 
     160                        " allowed when default_order is basestring type") 
     161                else: 
     162                    df = default_order 
     163                         
     164                ordering = dict([(v.lstrip('-'), [k, not v.startswith('-')]) 
     165                                 for k,v in enumerate(df)]) 
    147166            elif ordering and order: 
    148167                sort_ordering(ordering, order) 
  • branches/1.0/turbogears/tests/test_paginate.py

    r3735 r3744  
    266266        empty = paginate("data", limit=4)(empty) 
    267267        empty = expose()(empty) 
     268    # end of MyRoot ------------------------------------------------------------ 
    268269 
    269270 
     
    525526 
    526527    class MyRoot(RootController): 
    527         def basic(self, method=None): 
     528        def __common(self, method=None): 
    528529            if method == "Q": 
    529530                data = session.query(Address) 
     
    538539                      order=None, row_count=16) 
    539540            return dict(data=data, spy=spy) 
    540         basic = paginate("data", default_order="id")(basic) 
    541         basic = expose("turbogears.tests.paginate")(basic) 
    542  
    543         def reversed(self, method=None): 
    544             if method=="Q": 
    545                 data = session.query(Address) 
    546             elif method=="SR": 
    547                 data = SASelectResults(session.query(Address)) 
    548             elif method == "SO": 
    549                 data = SOAddress.select() 
    550             else: 
    551                 raise Exception("method must be 'Q' (Query) or 'SR' (SelectResults)") 
    552  
    553             spy = Spy(var_name='data', pages=[1,2], limit=10, page_count=2, 
    554                       order=None, row_count=16) 
    555             return dict(data=data, spy=spy) 
    556         reversed = paginate("data", default_order="id", default_reversed=True)(reversed) 
    557         reversed = expose("turbogears.tests.paginate")(reversed) 
     541 
     542        # default_order = basestring 
     543        basic1 = paginate("data", default_order="id")(__common) 
     544        basic1 = expose("turbogears.tests.paginate")(basic1) 
     545 
     546        # default_order = list 
     547        basic2 = paginate("data", default_order=["id"])(__common) 
     548        basic2 = expose("turbogears.tests.paginate")(basic2) 
     549 
     550        # default_order = basestring with default_reversed (deprecated) 
     551        reversed1 = paginate("data", default_order="id", default_reversed=True)(__common) 
     552        reversed1 = expose("turbogears.tests.paginate")(reversed1) 
     553 
     554        # default_order = basestring 
     555        reversed2 = paginate("data", default_order="-id")(__common) 
     556        reversed2 = expose("turbogears.tests.paginate")(reversed2) 
     557 
     558        # default_order = list with default_reversed (WRONG !!!!) 
     559        wrong_reversed = paginate("data", default_order=["id"], default_reversed=True)(__common) 
     560        wrong_reversed = expose("turbogears.tests.paginate")(wrong_reversed) 
     561 
     562        # default_order = list 
     563        reversed3 = paginate("data", default_order=["-id"])(__common) 
     564        reversed3 = expose("turbogears.tests.paginate")(reversed3) 
     565 
     566        # +/+ 
     567        default_compound_ordering1 = paginate("data", default_order=["city", "street"])(__common) 
     568        default_compound_ordering1 = expose("turbogears.tests.paginate")(default_compound_ordering1) 
     569 
     570        # +/- 
     571        default_compound_ordering2 = paginate("data", default_order=["city", "-street"])(__common) 
     572        default_compound_ordering2 = expose("turbogears.tests.paginate")(default_compound_ordering2) 
     573 
     574        # -/+ 
     575        default_compound_ordering3 = paginate("data", default_order=["-city", "street"])(__common) 
     576        default_compound_ordering3 = expose("turbogears.tests.paginate")(default_compound_ordering3) 
     577 
     578        # -/- 
     579        default_compound_ordering4 = paginate("data", default_order=["-city", "-street"])(__common) 
     580        default_compound_ordering4 = expose("turbogears.tests.paginate")(default_compound_ordering4) 
    558581 
    559582        def related(self): 
     
    566589        related = paginate("data", default_order="id")(related) 
    567590        related = expose("turbogears.tests.paginate")(related) 
     591 
     592    # end of MyRoot ------------------------------------------------------------ 
    568593 
    569594    def setUp(self): 
     
    577602 
    578603    def test_basic(self): 
     604        for test in "basic1", "basic2": 
     605            for method in "Q", "SR", "SO": 
     606                self.request("/%s/?method=%s" % (test, method)) 
     607                self.assert_order(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
     608                Spy.assert_ok(self.body, 'current_page', 1) 
     609                Spy.assert_ok(self.body, 'first_item', 1) 
     610                Spy.assert_ok(self.body, 'last_item', 10) 
     611                Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
     612 
     613                # old style 
     614                self.request("/%s/?method=%s&tg_paginate_no=2" % (test, method)) 
     615                self.assert_order(11, 12, 13, 14, 15, 16) 
     616                Spy.assert_ok(self.body, 'current_page', 2) 
     617                Spy.assert_ok(self.body, 'first_item', 11) 
     618                Spy.assert_ok(self.body, 'last_item', 16) 
     619                Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
     620 
     621                # new style 
     622                self.request("/%s/?method=%s&data_tgp_no=2" % (test, method)) 
     623                self.assert_order(11, 12, 13, 14, 15, 16) 
     624                Spy.assert_ok(self.body, 'current_page', 2) 
     625                Spy.assert_ok(self.body, 'first_item', 11) 
     626                Spy.assert_ok(self.body, 'last_item', 16) 
     627                Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
     628 
     629    def test_ordering(self): 
     630        for test in "basic1", "basic2": 
     631            for method in "Q", "SR", "SO": 
     632                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     633                    (test, method, quote(str({'street': [0, True]})))) 
     634                self.assert_order(16, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
     635                Spy.assert_ok(self.body, 'current_page', 1) 
     636                Spy.assert_ok(self.body, 'first_item', 1) 
     637                Spy.assert_ok(self.body, 'last_item', 10) 
     638                Spy.assert_ok(self.body, 'ordering', {'street': [0, True]}) 
     639 
     640                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     641                    (test, method, quote(str({'street': [0, True]})))) 
     642                self.assert_order(11, 12, 13, 14, 15, 1) 
     643                Spy.assert_ok(self.body, 'current_page', 2) 
     644                Spy.assert_ok(self.body, 'first_item', 11) 
     645                Spy.assert_ok(self.body, 'last_item', 16) 
     646                Spy.assert_ok(self.body, 'ordering', {'street': [0, True]}) 
     647 
     648    def test_default_reversed(self): 
     649        for test in "reversed1", "reversed2", "reversed3": 
     650            for method in "Q", "SR", "SO": 
     651                self.request("/%s/?method=%s" % (test, method)) 
     652                self.assert_order(16, 15, 14, 13, 12, 11, 10, 9, 8, 7) 
     653                Spy.assert_ok(self.body, 'current_page', 1) 
     654                Spy.assert_ok(self.body, 'first_item', 1) 
     655                Spy.assert_ok(self.body, 'last_item', 10) 
     656                Spy.assert_ok(self.body, 'ordering', {'id': [0, False]}) 
     657 
     658                self.request("/%s/?method=%s&data_tgp_no=2" % (test, method)) 
     659                self.assert_order(6, 5, 4, 3, 2, 1) 
     660                Spy.assert_ok(self.body, 'current_page', 2) 
     661                Spy.assert_ok(self.body, 'first_item', 11) 
     662                Spy.assert_ok(self.body, 'last_item', 16) 
     663                Spy.assert_ok(self.body, 'ordering', {'id': [0, False]}) 
     664 
     665    def test_invalid_default_reversed(self): 
    579666        for method in "Q", "SR", "SO": 
    580             self.request("/basic/?method=%s" % method) 
    581             self.assert_order(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
    582             Spy.assert_ok(self.body, 'current_page', 1) 
    583             Spy.assert_ok(self.body, 'first_item', 1) 
    584             Spy.assert_ok(self.body, 'last_item', 10) 
    585             Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
    586  
    587             # old style 
    588             self.request("/basic/?method=%s&tg_paginate_no=2" % method) 
    589             self.assert_order(11, 12, 13, 14, 15, 16) 
    590             Spy.assert_ok(self.body, 'current_page', 2) 
    591             Spy.assert_ok(self.body, 'first_item', 11) 
    592             Spy.assert_ok(self.body, 'last_item', 16) 
    593             Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
    594  
    595             # new style 
    596             self.request("/basic/?method=%s&data_tgp_no=2" % method) 
    597             self.assert_order(11, 12, 13, 14, 15, 16) 
    598             Spy.assert_ok(self.body, 'current_page', 2) 
    599             Spy.assert_ok(self.body, 'first_item', 11) 
    600             Spy.assert_ok(self.body, 'last_item', 16) 
    601             Spy.assert_ok(self.body, 'ordering', {'id': [0, True]}) 
    602  
    603     def test_ordering(self): 
     667            self.request("/wrong_reversed/?method=%s" % method) 
     668            print self.body 
     669            assert 'StandardError: default_reversed (deprecated) is only  allowed' in self.body 
     670 
     671    def test_reverse_ordering(self): 
     672        for test in "basic1", "basic2": 
     673            for method in "Q", "SR", "SO": 
     674                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     675                    (test, method, quote(str({'street': [0, False]})))) 
     676                self.assert_order(1, 15, 14, 13, 12, 11, 10, 9, 8, 7) 
     677                Spy.assert_ok(self.body, 'ordering', {'street': [0, False]}) 
     678 
     679                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     680                    (test, method, quote(str({'street': [0, False]})))) 
     681                self.assert_order(6, 5, 4, 3, 2, 16) 
     682                Spy.assert_ok(self.body, 'ordering', {'street': [0, False]}) 
     683 
     684    def test_compound_ordering(self): 
     685        for test in "basic1", "basic2": 
     686            for method in "Q", "SR", "SO": 
     687                # True/True 
     688                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     689                    (test, method, quote(str({'city': [0, True], 'street': [1, True]})))) 
     690                self.assert_order(16, 3, 9, 10, 12, 13, 1, 4, 7, 8) 
     691                Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, True]}) 
     692 
     693                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     694                    (test, method, quote(str({'city': [0, True], 'street': [1, True]})))) 
     695                self.assert_order(14, 15, 2, 5, 6, 11) 
     696                Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, True]}) 
     697 
     698                # True/False 
     699                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     700                    (test, method, quote(str({'city': [0, True], 'street': [1, False]})))) 
     701                self.assert_order(1, 13, 12, 10, 9, 3, 16, 15, 14, 8) 
     702                Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, False]}) 
     703 
     704                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     705                    (test, method, quote(str({'city': [0, True], 'street': [1, False]})))) 
     706                self.assert_order(7, 4, 11, 6, 5, 2) 
     707                Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, False]}) 
     708 
     709                # False/True 
     710                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     711                    (test, method, quote(str({'city': [0, False], 'street': [1, True]})))) 
     712                self.assert_order(2, 5, 6, 11, 4, 7, 8, 14, 15, 16) 
     713                Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, True]}) 
     714 
     715                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     716                    (test, method, quote(str({'city': [0, False], 'street': [1, True]})))) 
     717                self.assert_order(3, 9, 10, 12, 13, 1) 
     718                Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, True]}) 
     719 
     720                # False/False 
     721                self.request("/%s/?method=%s&tg_paginate_ordering=%s" % \ 
     722                    (test, method, quote(str({'city': [0, False], 'street': [1, False]})))) 
     723                self.assert_order(11, 6, 5, 2, 15, 14, 8, 7, 4, 1) 
     724                Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, False]}) 
     725 
     726                self.request("/%s/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
     727                    (test, method, quote(str({'city': [0, False], 'street': [1, False]})))) 
     728                self.assert_order(13, 12, 10, 9, 3, 16) 
     729                Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, False]}) 
     730 
     731    def test_default_compound_ordering_1(self): 
     732        # True/True 
    604733        for method in "Q", "SR", "SO": 
    605             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    606                 (method, quote(str({'street': [0, True]})))) 
    607             self.assert_order(16, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
    608             Spy.assert_ok(self.body, 'current_page', 1) 
    609             Spy.assert_ok(self.body, 'first_item', 1) 
    610             Spy.assert_ok(self.body, 'last_item', 10) 
    611             Spy.assert_ok(self.body, 'ordering', {'street': [0, True]}) 
    612  
    613             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    614                 (method, quote(str({'street': [0, True]})))) 
    615             self.assert_order(11, 12, 13, 14, 15, 1) 
    616             Spy.assert_ok(self.body, 'current_page', 2) 
    617             Spy.assert_ok(self.body, 'first_item', 11) 
    618             Spy.assert_ok(self.body, 'last_item', 16) 
    619             Spy.assert_ok(self.body, 'ordering', {'street': [0, True]}) 
    620  
    621     def test_default_reversed(self): 
    622         for method in "Q", "SR", "SO": 
    623             self.request("/reversed/?method=%s" % method) 
    624             self.assert_order(16, 15, 14, 13, 12, 11, 10, 9, 8, 7) 
    625             Spy.assert_ok(self.body, 'current_page', 1) 
    626             Spy.assert_ok(self.body, 'first_item', 1) 
    627             Spy.assert_ok(self.body, 'last_item', 10) 
    628             Spy.assert_ok(self.body, 'ordering', {'id': [0, False]}) 
    629  
    630             self.request("/reversed/?method=%s&data_tgp_no=2" % method) 
    631             self.assert_order(6, 5, 4, 3, 2, 1) 
    632             Spy.assert_ok(self.body, 'current_page', 2) 
    633             Spy.assert_ok(self.body, 'first_item', 11) 
    634             Spy.assert_ok(self.body, 'last_item', 16) 
    635             Spy.assert_ok(self.body, 'ordering', {'id': [0, False]}) 
    636  
    637     def test_reverse_ordering(self): 
    638         for method in "Q", "SR", "SO": 
    639             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    640                 (method, quote(str({'street': [0, False]})))) 
    641             self.assert_order(1, 15, 14, 13, 12, 11, 10, 9, 8, 7) 
    642             Spy.assert_ok(self.body, 'ordering', {'street': [0, False]}) 
    643  
    644             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    645                 (method, quote(str({'street': [0, False]})))) 
    646             self.assert_order(6, 5, 4, 3, 2, 16) 
    647             Spy.assert_ok(self.body, 'ordering', {'street': [0, False]}) 
    648  
    649     def test_compound_ordering(self): 
    650         for method in "Q", "SR", "SO": 
    651             # True/True 
    652             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    653                 (method, quote(str({'city': [0, True], 'street': [1, True]})))) 
     734            self.request("/default_compound_ordering1/?method=%s" % method) 
    654735            self.assert_order(16, 3, 9, 10, 12, 13, 1, 4, 7, 8) 
    655736            Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, True]}) 
    656737 
    657             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    658                 (method, quote(str({'city': [0, True], 'street': [1, True]})))) 
     738            self.request("/default_compound_ordering1/?method=%s&tg_paginate_no=2" % method) 
    659739            self.assert_order(14, 15, 2, 5, 6, 11) 
    660740            Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, True]}) 
    661741 
    662             # True/False 
    663             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    664                 (method, quote(str({'city': [0, True], 'street': [1, False]})))) 
     742    def test_default_compound_ordering_2(self): 
     743        # True/False 
     744        for method in "Q", "SR", "SO": 
     745            self.request("/default_compound_ordering2/?method=%s" % method) 
    665746            self.assert_order(1, 13, 12, 10, 9, 3, 16, 15, 14, 8) 
    666747            Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, False]}) 
    667748 
    668             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    669                 (method, quote(str({'city': [0, True], 'street': [1, False]})))) 
     749            self.request("/default_compound_ordering2/?method=%s&tg_paginate_no=2" % method) 
    670750            self.assert_order(7, 4, 11, 6, 5, 2) 
    671751            Spy.assert_ok(self.body, 'ordering', {'city': [0, True], 'street': [1, False]}) 
    672752 
    673             # False/True 
    674             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    675                 (method, quote(str({'city': [0, False], 'street': [1, True]})))) 
     753    def test_default_compound_ordering_3(self): 
     754        # False/True 
     755        for method in "Q", "SR", "SO": 
     756            self.request("/default_compound_ordering3/?method=%s" % method) 
    676757            self.assert_order(2, 5, 6, 11, 4, 7, 8, 14, 15, 16) 
    677758            Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, True]}) 
    678759 
    679             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    680                 (method, quote(str({'city': [0, False], 'street': [1, True]})))) 
     760            self.request("/default_compound_ordering3/?method=%s&tg_paginate_no=2" % method) 
    681761            self.assert_order(3, 9, 10, 12, 13, 1) 
    682762            Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, True]}) 
    683763 
    684             # False/False 
    685             self.request("/basic/?method=%s&tg_paginate_ordering=%s" % \ 
    686                 (method, quote(str({'city': [0, False], 'street': [1, False]})))) 
     764    def test_default_compound_ordering_4(self): 
     765        # False/False 
     766        for method in "Q", "SR", "SO": 
     767            self.request("/default_compound_ordering4/?method=%s" % method) 
    687768            self.assert_order(11, 6, 5, 2, 15, 14, 8, 7, 4, 1) 
    688769            Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, False]}) 
    689770 
    690             self.request("/basic/?method=%s&tg_paginate_no=2&tg_paginate_ordering=%s" % \ 
    691                 (method, quote(str({'city': [0, False], 'street': [1, False]})))) 
     771            self.request("/default_compound_ordering4/?method=%s&tg_paginate_no=2" % method) 
    692772            self.assert_order(13, 12, 10, 9, 3, 16) 
    693773            Spy.assert_ok(self.body, 'ordering', {'city': [0, False], 'street': [1, False]})