app/soc/views/helper/lists.py
branchgae-fetch-limitation-fix
changeset 2315 29fea493cd56
parent 2313 c39a81bce1bd
child 2354 4cc66ab098e8
equal deleted inserted replaced
2313:c39a81bce1bd 2315:29fea493cd56
    58   return DEF_DEFAULT_PAGINATION
    58   return DEF_DEFAULT_PAGINATION
    59 
    59 
    60 
    60 
    61 OFFSET_KEY = 'offset_%d'
    61 OFFSET_KEY = 'offset_%d'
    62 LIMIT_KEY = 'limit_%d'
    62 LIMIT_KEY = 'limit_%d'
    63 OFFSET_LINKID_KEY = 'offset_linkid_%d'
    63 OFFSET_KEYNAME_KEY = 'offset_keyname_%d'
    64 REVERSE_DIRECTION_KEY = 'reverse_sort_direction_%d'
    64 REVERSE_DIRECTION_KEY = 'reverse_sort_direction_%d'
    65 
    65 
    66 
    66 
    67 def makeOffsetKey(limit_idx):
    67 def makeOffsetKey(limit_idx):
    68   return OFFSET_KEY % limit_idx
    68   return OFFSET_KEY % limit_idx
    70 
    70 
    71 def makeLimitKey(limit_idx):
    71 def makeLimitKey(limit_idx):
    72   return LIMIT_KEY % limit_idx
    72   return LIMIT_KEY % limit_idx
    73 
    73 
    74 
    74 
    75 def makeOffsetLinkidKey(limit_idx):
    75 def makeOffsetKeynameKey(limit_idx):
    76   return OFFSET_LINKID_KEY % limit_idx
    76   return OFFSET_KEYNAME_KEY % limit_idx
    77 
    77 
    78 
    78 
    79 def makeReverseDirectionKey(limit_idx):
    79 def makeReverseDirectionKey(limit_idx):
    80   return REVERSE_DIRECTION_KEY % limit_idx
    80   return REVERSE_DIRECTION_KEY % limit_idx
    81 
    81 
   118     limit = min(DEF_MAX_DEV_PAGINATION, limit)
   118     limit = min(DEF_MAX_DEV_PAGINATION, limit)
   119   else:
   119   else:
   120     limit = min(DEF_MAX_PAGINATION, limit)
   120     limit = min(DEF_MAX_PAGINATION, limit)
   121 
   121 
   122   result = dict(limit=limit, offset=offset)
   122   result = dict(limit=limit, offset=offset)
   123   offset_linkid = request.GET.get(makeOffsetLinkidKey(list_index),
   123   offset_keyname_key = makeOffsetLinkidKey(list_index)
   124                                   '')
   124   offset_keyname = request.GET.get(offset_keyname_key, '')
   125   # TODO(dbentley): URL unescape
   125   # TODO(dbentley): URL unescape
   126   result['offset_linkid'] = offset_linkid
   126   result['offset_keyname'] = offset_keyname
   127 
   127 
   128   reverse_direction = makeReverseDirectionKey(list_index) in request.GET
   128   reverse_direction = makeReverseDirectionKey(list_index) in request.GET
   129   result['reverse_direction'] = reverse_direction
   129   result['reverse_direction'] = reverse_direction
   130 
   130 
   131   return result
   131   return result
   140         i for i in request.GET.iteritems() if
   140         i for i in request.GET.iteritems() if
   141         i[0].startswith('offset_') or i[0].startswith('limit_'))
   141         i[0].startswith('offset_') or i[0].startswith('limit_'))
   142     self.idx = list_idx
   142     self.idx = list_idx
   143     self.base_params[makeLimitKey(self.idx)] = limit
   143     self.base_params[makeLimitKey(self.idx)] = limit
   144 
   144 
   145   def create(self, offset_linkid=None, export=False, reverse_direction=False):
   145   def create(self, offset_keyname=None, export=False, reverse_direction=False):
   146     params = self.base_params.copy()
   146     params = self.base_params.copy()
   147     if offset_linkid is not None:
   147     if offset_linkid is not None:
   148       # TODO(dbentley): URL encode
   148       # TODO(dbentley): URL encode
   149       if offset_linkid == '':
   149       if offset_linkid == '':
   150         try:
   150         try:
   191       'next': url to next page
   191       'next': url to next page
   192       'first': offset of the first item in the list
   192       'first': offset of the first item in the list
   193       'last': offset of the last item in the list
   193       'last': offset of the last item in the list
   194     }
   194     }
   195   """
   195   """
   196   # TODO(dbentley): this appears to be unnecessary indirection,
   196 
   197   # as we only use this logic for getForFields, which is never overridden
       
   198   logic = params['logic']
   197   logic = params['logic']
   199 
   198 
   200   limit_key = makeLimitKey(idx)
   199   limit_key = makeLimitKey(idx)
   201   # offset_key = makeOffsetKey(idx)
   200   offset_key = makeOffsetKey(idx)
   202   # offset_linkid_key = makeOffsetLinkidKey(idx) 
   201   offset_keyname_key = makeOffsetKeynameKey(idx)
   203   # reverse_direction_key = makeReverseDirectionKey(idx)
   202   reverse_direction_key = makeReverseDirectionKey(idx)
   204 
   203 
   205   list_params = getListParameters(request, idx)
   204   list_params = getListParameters(request, idx)
   206   limit, offset = list_params['limit'], list_params['offset']
   205 
   207   offset_linkid = list_params['offset_linkid']
   206   limit = list_params['limit']
       
   207   offset = list_params['offset']
       
   208   offset_keyname = list_params['offset_keyname']
   208   reverse_direction = list_params['reverse_direction']
   209   reverse_direction = list_params['reverse_direction']
   209   pagination_form = makePaginationForm(request, list_params['limit'],
   210 
   210                                        limit_key)
   211   pagination_form = makePaginationForm(request, limit, limit_key)
   211 
   212 
   212   if offset_linkid:
   213   if offset_keyname:
   213     if filter is None:
   214     if filter is None:
   214       filter = {}
   215       filter = {}
   215 
   216 
   216     if reverse_direction:
   217     if reverse_direction:
   217       filter['link_id <'] = offset_linkid
   218       filter['__key__ <'] = offset_keyname
   218     else:
   219     else:
   219       filter['link_id >'] = offset_linkid
   220       filter['__key__ >'] = offset_keyname
   220 
   221 
   221     if order is None:
   222     if order is None:
   222       order = []
   223       order = []
   223     if reverse_direction:
   224     if reverse_direction:
   224       order.append('-link_id')
   225       order.append('-__key__')
   225     else:
   226     else:
   226       order.append('link_id')
   227       order.append('__key__')
   227 
       
   228 
       
   229 
   228 
   230   # Fetch one more to see if there should be a 'next' link
   229   # Fetch one more to see if there should be a 'next' link
   231   data = logic.getForFields(filter=filter, limit=limit+1, offset=offset,
   230   data = logic.getForFields(filter=filter, limit=limit+1, offset=offset,
   232                             order=order)
   231                             order=order)
   233 
   232 
   250 
   249 
   251   # Calculating should_have_previous_link is tricky. It's possible we could
   250   # Calculating should_have_previous_link is tricky. It's possible we could
   252   # be creating a previous link to a page that would have 0 entities.
   251   # be creating a previous link to a page that would have 0 entities.
   253   # That would be suboptimal; what's a better way?
   252   # That would be suboptimal; what's a better way?
   254   should_have_previous_link = False
   253   should_have_previous_link = False
   255   if offset_linkid:
   254   if offset_keyname:
   256     should_have_previous_link = True
   255     should_have_previous_link = True
   257   if reverse_direction and not more:
   256   if reverse_direction and not more:
   258     should_have_previous_link = False
   257     should_have_previous_link = False
   259 
   258 
   260   if data:
   259   if data:
   261     first_displayed_item = data[0]
   260     first_key_name = data[0].key().name_or_id()
   262     last_displayed_item = data[-1]
   261     last_key_name = data[-1].key().name_or_id()
   263   else:
   262   else:
   264     class Dummy(object):
   263     first_key_name = None
   265       pass
   264     last_key_name = None
   266     first_displayed_item = last_displayed_item = Dummy()
   265 
   267     first_displayed_item.link_id = None
       
   268   newest = next = prev = export_link = ''
   266   newest = next = prev = export_link = ''
   269 
   267 
   270   link_creator = LinkCreator(request, idx, limit)
   268   link_creator = LinkCreator(request, idx, limit)
   271 
   269 
   272   if params.get('list_key_order'):
   270   if params.get('list_key_order'):
   273     export_link = link_creator.create(export=True)
   271     export_link = link_creator.create(export=True)
   274 
   272 
   275   if should_have_next_link:
   273   if should_have_next_link:
   276     next = link_creator.create(offset_linkid=last_displayed_item.link_id)
   274     next = link_creator.create(offset_keyname=last_key_name)
   277 
   275 
   278   if should_have_previous_link:
   276   if should_have_previous_link:
   279     prev = link_creator.create(offset_linkid=first_displayed_item.link_id,
   277     prev = link_creator.create(offset_keyname=first_key_name,
   280                                reverse_direction=True)
   278                                reverse_direction=True)
   281 
   279 
   282   newest = link_creator.create(offset_linkid='')
   280   newest = link_creator.create(offset_keyname='')
   283 
   281 
   284   # TODO(dbentley): add a "last" link (which is now possible because we can
   282   # TODO(dbentley): add a "last" link (which is now possible because we can
   285   # query with a reverse linkid sorting
   283   # query with a reverse keyname sorting
   286 
   284 
   287   content = {
   285   content = {
   288       'idx': idx,
   286       'idx': idx,
   289       'data': data,
   287       'data': data,
   290       'export': export_link,
   288       'export': export_link,
   291       'first': first_displayed_item.link_id,
   289       'first': first_key_name,
   292       'last': last_displayed_item.link_id,
   290       'last': last_key_name,
   293       'logic': logic,
   291       'logic': logic,
   294       'limit': limit,
   292       'limit': limit,
   295       'newest': newest,
   293       'newest': newest,
   296       'next': next,
   294       'next': next,
   297       'pagination_form': pagination_form,
   295       'pagination_form': pagination_form,