{"id":3880,"date":"2010-08-23T18:36:38","date_gmt":"2010-08-23T09:36:38","guid":{"rendered":"http:\/\/www.gesource.jp\/weblog\/?p=3880"},"modified":"2017-07-16T15:07:21","modified_gmt":"2017-07-16T06:07:21","slug":"google-app-engine-version-1-3-6%e3%81%ae%e6%96%b0%e6%a9%9f%e8%83%bd","status":"publish","type":"post","link":"https:\/\/www.gesource.jp\/weblog\/?p=3880","title":{"rendered":"Google App Engine Version 1.3.6\u306e\u65b0\u6a5f\u80fd"},"content":{"rendered":"<p>Google App Engine Version 1.3.6\u306e\u65b0\u6a5f\u80fd\u3092\u958b\u767a\u74b0\u5883\u3067\u8a66\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u306fKay-Framework\u3092\u4f7f\u7528\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>(1)Results of datastore count() queries and offsets for all datastore queries are no longer capped at 1000.<\/p>\n<p>\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u306e\u30af\u30a8\u30ea\u30fc\u3068\u30ab\u30a6\u30f3\u30c8\u306e1000\u4ef6\u306e\u5236\u9650\u3092\u89e3\u9664\u3055\u308c\u307e\u3057\u305f\u3002<\/p>\n<p>\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u306e\u30af\u30a8\u30ea\u30fc\u3068\u30ab\u30a6\u30f3\u30c8\u306e\u53d6\u5f97\u4ef6\u6570\u304c1000\u4ef6\u307e\u3067\u306b\u5236\u9650\u3055\u308c\u3066\u3044\u307e\u3057\u305f\u3002<br \/>\n\u3053\u306e1000\u4ef6\u306e\u5236\u9650\u304c\u89e3\u9664\u3055\u308c\u307e\u3057\u305f\u3002<br \/>\nCPU\u30af\u30aa\u30fc\u30bf\u3068\u30ea\u30af\u30a8\u30b9\u30c8\u6642\u9593\u306e\u8a31\u3059\u7bc4\u56f2\u3067\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>Query\u3068GqlQuery\u306e\u57fa\u5e95\u30af\u30e9\u30b9(&#95;BaseQuery)\u3067\u3001\u53d6\u5f97\u3067\u304d\u308b\u4ef6\u6570\u306e\u521d\u671f\u5024\u304c1000\u4ef6\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059\u3002<\/p>\n<pre><code>class _BaseQuery(object):\n  def count(self, limit=1000, **kwargs):\n<\/code><\/pre>\n<p>\u3053\u306e\u305f\u3081\u5f15\u6570\u3067\u5236\u9650\u3092\u6307\u5b9a\u3057\u306a\u3044\u5834\u5408\u306f\u3001\u53d6\u5f97\u3067\u304d\u308b\u4ef6\u6570\u306f\u5f93\u6765\u3068\u540c\u3058\u30671000\u4ef6\u307e\u3067\u3067\u3059\u3002<\/p>\n<pre><code>count = models.Comment.all().count() #=&gt;\u6700\u59271000\n<\/code><\/pre>\n<p>1000\u4ef6\u4ee5\u4e0a\u53d6\u5f97\u3057\u305f\u3044\u5834\u5408\u306f\u3001\u5f15\u6570\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<pre><code>count = models.Comment.all().count(99999) #=&gt;\u6700\u592799999\n<\/code><\/pre>\n<p>(2) Users can now serve custom static error pages for over&#95;quota, dos&#95;api&#95;denial and default cases.<\/p>\n<p>\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u8a2d\u5b9a\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3057\u305f\u3002<br \/>\n\u53c2\u7167\uff1a<a href=\"http:\/\/code.google.com\/intl\/en\/appengine\/docs\/python\/config\/appconfig.html#Custom_Error_Responses\">Custom Error Responses<\/a><\/p>\n<p>app.yaml<\/p>\n<pre><code>error_handlers:\n  # \u6a19\u6e96\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\n  - file: default_error.html\n<\/code><\/pre>\n<p>\u30a8\u30e9\u30fc\u3054\u3068\u306b\u8868\u793a\u3059\u308b\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u3092\u8a2d\u5b9a\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>app.yaml<\/p>\n<pre><code>error_handlers:\n  # \u6a19\u6e96\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\n  - file: default_error.html\n\n  # \u30ea\u30bd\u30fc\u30b9\u306e\u5272\u308a\u5f53\u3066\u3092\u8d85\u3048\u305f\u3068\u304d\n  - error_code: over_quota\n    file: over_quota.html\n\n  # DoS Protection\n  - error_code: dos_api_denial:\n    file: dos_api_denial.html\n\n  # \u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u306e\u3068\u304d\n  - error_code: timeout:\n    file: timeout.html\n<\/code><\/pre>\n<p>(3)Automatic image thumbnailing is now available in the Images API using get&#95;serving&#95;url().<\/p>\n<p>get&#95;serving&#95;url()\u3067\u753b\u50cf\u306e\u30b5\u30a4\u30ba\u5909\u66f4\u3084\u5207\u308a\u629c\u304d\u304c\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3057\u305f\u3002<br \/>\n\u53c2\u7167\uff1a<a href=\"http:\/\/code.google.com\/intl\/en\/appengine\/docs\/python\/images\/functions.html#Image_get_serving_url\">get&#95;serving&#95;url(blob&#95;key, size=None, crop=False)<\/a><\/p>\n<p>\u300c<a href=\"http:\/\/www.ianlewis.org\/jp\/google-app-engine-136\">Google App Engine 1.3.6 &#8211; Ian Lewis<\/a>\u300d\u306b\u3088\u308b\u3068\u3001\u5225\u306e\u30a4\u30f3\u30d5\u30e9\u3092\u4f7f\u3046\u305f\u3081\u306bGoogleAppEngine\u306e\u30af\u30aa\u30fc\u30bf\u306e\u5236\u9650\u304c\u304b\u304b\u3089\u306a\u3044\u305d\u3046\u3067\u3059\u3002<\/p>\n<p>\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u306f\u3001<a href=\"http:\/\/code.google.com\/intl\/en\/appengine\/docs\/python\/images\/functions.html#Image_get_serving_url\">get&#95;serving&#95;url(blob&#95;key, size=None, crop=False)<\/a>\u3092\u4f7f\u7528\u3057\u305f\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3067\u3059\u3002<br \/>\n\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3055\u308c\u753b\u50cf\u306b\u5bfe\u3057\u3066\u30b5\u30a4\u30ba\u5909\u66f4\u3057\u305f\u308a\u3001\u5207\u308a\u629c\u304d\u3092\u3057\u305f\u753b\u50cf\u306eURL\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<\/p>\n<p>myapp\/urls.py<\/p>\n<pre><code>view_groups = [\n  ViewGroup(\n    Rule('\/', endpoint='index', view='myapp.views.index'),\n    Rule('\/upload', endpoint='upload', view=('myapp.views.UploadHandler', (), {})),\n  )\n]\n<\/code><\/pre>\n<p>myapp\/views.py<\/p>\n<pre><code>from werkzeug import Response\nfrom kay.utils import render_to_response, url_for\nfrom kay.handlers import blobstore_handlers\nfrom google.appengine.ext import blobstore\nfrom google.appengine.api import images\n\ndef index(request):\n    upload_url = blobstore.create_upload_url(url_for('myapp\/upload'))\n    blob_key = request.values.get('blob_key')\n    d = {'upload_url': upload_url}\n    if blob_key:\n        from google.appengine.api.images import get_serving_url\n        d['blob_key'] = blob_key\n        # \u30b5\u30a4\u30ba\u5909\u66f4\n        d['resize_url'] = get_serving_url(blob_key, 64)\n        # \u5207\u308a\u629c\u304d\n        d['crop_url'] = get_serving_url(blob_key, 160, True)\n\n    return render_to_response(\"myapp\/index.html\", d)\n\nclass UploadHandler(blobstore_handlers.BlobstoreUploadHandler):\n    def post(self):\n        # 'file' is file upload field in the form                                                                                                              \n        upload_files = self.get_uploads('file')\n        blob_info = upload_files[0]\n        headers = {'Location': url_for('myapp\/index', blob_key=blob_info.key())}\n        return Response(None, headers=headers, status=302)\n<\/code><\/pre>\n<p>myapp\/templates\/index.html<\/p>\n<pre><code>&lt;!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/html4\/loose.dtd\"&gt;\n&lt;html&gt;\n&lt;head&gt;\n&lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\n&lt;title&gt;Top Page - myapp&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n\n{% if blob_key %}\nUpload succeeded.&lt;br\/&gt;\n&lt;a href=\"{{ resize_url }}\"&gt;View resizing&lt;\/a&gt;&lt;br \/&gt;\n&lt;a href=\"{{ crop_url }}\"&gt;View cropping&lt;\/a&gt;&lt;br \/&gt;\n{% endif %}\n\n&lt;form action=\"{{ upload_url }}\" method=\"POST\" enctype=\"multipart\/form-data\"&gt;\nUpload File: &lt;input type=\"file\" name=\"file\"&gt;&lt;br&gt;\n&lt;input type=\"submit\" name=\"submit\" value=\"Submit\"&gt;\n&lt;\/form&gt;\n\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>(4)Multitenancy is now supported in the datastore, allowing better compartmentalization of user data.<\/p>\n<p>\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u306e\u540d\u524d\u7a7a\u9593\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u307e\u3057\u305f\u3002<br \/>\n\u53c2\u7167\uff1a<a href=\"http:\/\/code.google.com\/intl\/ja\/appengine\/docs\/python\/multitenancy\/\">Multitenancy and the Namespaces Python API &#8211; Google App Engine &#8211; Google Code<\/a><\/p>\n<pre><code>from google.appengine.api import namespace_manager\nnamespace = namespace_manager.get_namespace()\n\nnamespace_manager.set_namespace('A')  # \u540d\u524d\u7a7a\u9593\u3092\u300cA\u300d\u306b\u8a2d\u5b9a\ndo_something() #\u540d\u524d\u7a7a\u9593\u300cA\u300d\u3067\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u3092\u64cd\u4f5c\n\nnamespace_manager.set_namespace('B')  # \u540d\u524d\u7a7a\u9593\u3092\u300cB\u300d\u306b\u8a2d\u5b9a\ndo_something() #\u540d\u524d\u7a7a\u9593\u300cB\u300d\u3067\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u3092\u64cd\u4f5c\n\nnamespace_manager.set_namespace(namespace)  # \u540d\u524d\u7a7a\u9593\u3092\u5143\u306b\u623b\u3059\n<\/code><\/pre>\n<p>\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u306f\u3001\u540d\u524d\u7a7a\u9593\u3092\u4f7f\u7528\u3057\u305f\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3067\u3059\u3002<br \/>\n\u540d\u524d\u7a7a\u9593(&#8216;-global-&#8216;, &#8216;foo&#8217;, &#8216;bar&#8217;)\u306e\u3044\u305a\u308c\u304b\u306e\u30ab\u30a6\u30f3\u30bf\u30fc\u30921\u5897\u52a0\u3057\u3001\u5897\u52a0\u3057\u305f\u540d\u524d\u7a7a\u9593\u3068\u30ab\u30a6\u30f3\u30bf\u30fc\u306e\u5024\u3092\u8868\u793a\u3057\u307e\u3059\u3002<\/p>\n<p>myapp\/views.py<\/p>\n<pre><code>from werkzeug import Response\nfrom kay.utils import render_to_response, url_for\nfrom google.appengine.ext import db\nfrom google.appengine.api import namespace_manager\nimport random\n\nclass Counter(db.Model):\n    \"\"\"\u30ab\u30a6\u30f3\u30bf\u30fc\"\"\"\n    count = db.IntegerProperty()\n\ndef update_counter(name):\n    \"\"\"name\u306e\u30ab\u30a6\u30f3\u30bf\u30fc\u30921\u5897\u52a0\u3059\u308b\"\"\"\n    def _update_counter(name):\n        counter = Counter.get_by_key_name(name)\n        if counter is None:\n            counter = Counter(key_name=name);\n            counter.count = 1\n        else:\n            counter.count = counter.count + 1\n        counter.put()\n        return counter.count\n    return db.run_in_transaction(_update_counter, name)\n\ndef index(request):\n    \"\"\"\n    \u540d\u524d\u7a7a\u9593('-global-', 'foo', 'bar')\u306e\u3044\u305a\u308c\u304b\u306e\u30ab\u30a6\u30f3\u30bf\u30fc\u30921\u5897\u52a0\u3057\u3001\n    \u5897\u52a0\u3057\u305f\u540d\u524d\u7a7a\u9593\u3068\u30ab\u30a6\u30f3\u30bf\u30fc\u306e\u5024\u3092\u8868\u793a\u3059\u308b\n    \"\"\"\n    # \u540d\u524d\u7a7a\u9593\u306e\u30ea\u30b9\u30c8\n    ns_list = ('-global-', 'foo', 'bar')\n    # \u540d\u524d\u7a7a\u9593\u306e\u30ea\u30b9\u30c8\u304b\u3089\u30e9\u30f3\u30c0\u30e0\u306b\u53d6\u5f97\n    d = {'ns': random.choice(ns_list)}\n    # \u73fe\u5728\u306e\u540d\u524d\u7a7a\u9593\n    namespace = namespace_manager.get_namespace()\n    try:\n        # \u7de8\u96c6\u3059\u308b\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u306e\u540d\u524d\u7a7a\u9593\u3092\u8a2d\u5b9a\n        namespace_manager.set_namespace(d['ns'])\n        # \u30ab\u30a6\u30f3\u30bf\u30fc\u3092\u5897\u52a0\u3057\u3066\u7d50\u679c\u3092\u53d6\u5f97\n        d['count'] = update_counter('SomeRequest')\n    finally:\n        # \u540d\u524d\u7a7a\u9593\u3092\u5143\u306b\u623b\u3059\n        namespace_manager.set_namespace(namespace)\n    return render_to_response('myapp\/index.html', d)\n<\/code><\/pre>\n<p>myapp\/templates\/index.html<\/p>\n<pre><code>&lt;!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 4.01 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/html4\/loose.dtd\"&gt;\n&lt;html&gt;\n&lt;head&gt;\n&lt;meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\"&gt;\n&lt;title&gt;Top Page - myapp&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;p&gt;namespace = {{ns}}&lt;\/p&gt;\n&lt;p&gt;count = {{count}}&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>(5)Added a pause queue button to the task queue details page in the Admin Console.<\/p>\n<p>\u7ba1\u7406\u753b\u9762\u306e\u300cTask Queues\u300d\u306b\u300cPause Queue\u300d\u30dc\u30bf\u30f3\u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.gesource.jp\/weblog\/wp-content\/uploads\/2010\/08\/pause_queue.gif?w=730\" alt=\"\" \/><\/p>\n<p>(6)Historical graphs have been added to all of the dashboard graphs in the Admin Console.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.gesource.jp\/weblog\/wp-content\/uploads\/2010\/08\/historical.gif?w=730\" alt=\"\" \/><br \/>\n\u3053\u306e\u30dc\u30bf\u30f3\u304c\u8ffd\u52a0\u3055\u308c\u305f\uff1f<\/p>\n<p>(7)New method to allocate datastore ids in a given range: db.allocate_id_range().<\/p>\n<p>\u4e0e\u3048\u3089\u308c\u305f\u7bc4\u56f2\u3067\u30c7\u30fc\u30bf\u30b9\u30c8\u30a2\u306eid\u3092\u5272\u308a\u5f53\u3066\u308b\u65b0\u3057\u3044\u30e1\u30bd\u30c3\u30c9 db.allocate_id_range() \u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002<br \/>\n\u53c2\u7167\uff1a<a href=\"http:\/\/code.google.com\/intl\/en\/appengine\/docs\/python\/datastore\/functions.html#allocate_id_range\">db.allocate_id_range()<\/a><\/p>\n<p>(8)New db method is_in_transaction() determines if a transaction is still open.<\/p>\n<p>\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u4e2d\u304b\u3069\u3046\u304b\u3092\u53d6\u5f97\u3059\u308b\u65b0\u3057\u3044\u30e1\u30bd\u30c3\u30c9 db.is_in_transaction() \u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002<br \/>\n\u53c2\u7167\uff1a<a href=\"http:\/\/code.google.com\/intl\/en\/appengine\/docs\/python\/datastore\/functions.html#is_in_transaction\">db.is_in_transaction()<\/a><\/p>\n<p>(9)Increased several rate limited quotas for free applications.<\/p>\n<p>\u7121\u6599\u67a0\u304c\u5897\u3048\u307e\u3057\u305f\u3002<\/p>\n<p>(10) Remote API now supports the Blobstore API.<\/p>\n<p>\u30ea\u30e2\u30fc\u30c8API\u304c\u65b0\u3057\u304fBlobstore API\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>(11) Content-range headers are supported on Blobstore downloads.<\/p>\n<p>\u82f1\u8a9e\u306b\u306f\u81ea\u4fe1\u304c\u3042\u308a\u307e\u305b\u3093\u3002(\u6c57<br \/>\n\u9593\u9055\u3044\u304c\u3042\u308c\u3070\u6559\u3048\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Google App Engine Version 1.3.6\u306e\u65b0\u6a5f\u80fd\u3092\u958b\u767a\u74b0\u5883\u3067\u8a66\u3057\u307e\u3057\u305f\u3002 \u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u306fKay-Framework\u3092\u4f7f\u7528\u3057\u3066\u3044\u307e\u3059\u3002 (1)Results of datastore count() &#8230;<\/p>\n<p><a href=\"https:\/\/www.gesource.jp\/weblog\/?p=3880\" class=\"more-link\">Continue reading &lsquo;Google App Engine Version 1.3.6\u306e\u65b0\u6a5f\u80fd&rsquo; &raquo;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[96,95],"tags":[68,94,143],"class_list":["post-3880","post","type-post","status-publish","format-standard","hentry","category-googleappengine","category-kay-programming","tag-google-app-engine","tag-kay","tag-python"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=\/wp\/v2\/posts\/3880","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3880"}],"version-history":[{"count":0,"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=\/wp\/v2\/posts\/3880\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3880"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3880"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gesource.jp\/weblog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3880"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}