3 # Copyright 2008 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
18 """Suggestion Box - An example paging application.
20 A simple Suggestion Box application that demonstrates
21 paging by using the __key__ property provided for every
32 import wsgiref
.handlers
34 from google
.appengine
.ext
import webapp
35 from google
.appengine
.ext
.webapp
import template
36 from google
.appengine
.ext
import db
37 from google
.appengine
.api
import users
38 from google
.appengine
.ext
.webapp
.util
import login_required
39 from time
import mktime
45 class SuggestionByKey(db
.Model
):
47 A suggestion in the suggestion box, which we want to display
48 in the order they were created.
50 suggestion
= db
.StringProperty()
51 created
= db
.DateTimeProperty(auto_now_add
=True)
54 def encodebookmark(created
, key
):
56 From the created timestamp and the key for an entity create
57 a base64 encoded bookmark that can be used for paging.
60 created: datetime when the entity was created.
61 key: db.Key() of the entity.
64 A base64 encoded representation of the values.
66 timestamp
= mktime(created
.timetuple())+1e-6*created
.microsecond
67 return base64
.b64encode("%f|%s" % (timestamp
, key
))
70 def decodebookmark(b64bookmark
):
72 Takes a string encoded by 'encodebookmark' and reverses
76 A base64 encoded representation of the values.
81 created: datetime when the entity was created.
82 key: db.Key() of the entity.
84 timestamp
, key
= base64
.b64decode(b64bookmark
).split('|')
85 created
= datetime
.datetime
.fromtimestamp(float(timestamp
))
89 class SuggestionByKeyHandler(webapp
.RequestHandler
):
91 Handles the creation of a single Suggestion, and the display
92 of suggestions broken into PAGESIZE pages.
97 bookmark
= self
.request
.get('bookmark')
100 created
, key
= decodebookmark(bookmark
)
101 logging
.info('key = %s, created = %s' % (key
, created
))
102 query
= SuggestionByKey
.gql(
103 ' WHERE created = :created AND __key__ >= :key ORDER BY __key__ ASC',
104 created
= created
, key
= db
.Key(key
))
105 suggestions
= query
.fetch(PAGESIZE
+1)
106 logging
.info(type(suggestions
))
107 if len(suggestions
) < (PAGESIZE
+ 1):
108 logging
.info('Going for more entities since we only got %d' % len(suggestions
))
109 remainder
= PAGESIZE
+ 1 - len(suggestions
)
110 query
= SuggestionByKey
.gql(
111 'WHERE created < :created ORDER BY created DESC, __key__ ASC',
113 moresuggestions
= query
.fetch(remainder
)
114 logging
.info('Got %d more' % len(moresuggestions
))
115 suggestions
+= moresuggestions
116 logging
.info('For a total of %d entities' % len(suggestions
))
118 query
= SuggestionByKey
.gql('ORDER BY created DESC, __key__ ASC')
119 suggestions
= query
.fetch(PAGESIZE
+1)
120 if len(suggestions
) == PAGESIZE
+1:
121 next
= encodebookmark(suggestions
[-1].created
, suggestions
[-1].key())
122 suggestions
= suggestions
[:PAGESIZE
]
124 template_values
= {'next': next
, 'suggestions': suggestions
}
125 template_file
= os
.path
.join(os
.path
.dirname(__file__
), 'suggestion.html')
126 self
.response
.out
.write(template
.render(template_file
, template_values
))
129 s
= SuggestionByKey(suggestion
= self
.request
.get('suggestion'))
131 self
.redirect('/key/')
134 class SuggestionByKeyPopulate(webapp
.RequestHandler
):
136 Handles populating the datastore with some sample
137 Suggestions to see how the paging works.
140 now
= datetime
.datetime
.now()
142 s
= SuggestionByKey(suggestion
= 'Suggestion %d' % i
, created
= now
)
144 self
.redirect('/key/')
148 application
= webapp
.WSGIApplication([
149 ('/key/pop/', SuggestionByKeyPopulate
),
150 ('/key/', SuggestionByKeyHandler
)
152 wsgiref
.handlers
.CGIHandler().run(application
)
155 if __name__
== '__main__':