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 |
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, |