2016年5月29日日曜日

GAE/P Django タスクキューの 403エラー対策

GAE/Pのタスクキューは、通常、このように使います。

1.メインのプログラムで、キューに入れる

 [views.py]
 def hoge(request):
  …
  taskqueue.add(url='/task', params={'key': 'var'})
  …

2.Task Queue Service が /task に HTTPリクエストを送る

3.URLディスパッチで、タスクを起動

 [urls.py]
 url(r'^task$', views.task),

4.タスク処理を実行

 [views.py]
 def task(request):
  … あれこれ
  return HttpResponse()

でも、タスク処理が実行されず、しばし、悩みました。

開発サーバーのログを見てると、403エラーで弾かれてる??
ググッてみても、Adminでログインしろとか、トンチンカンな答えばかり..

結局は、CSRF絡みでした。
 http://docs.djangoproject.jp/en/latest/ref/contrib/csrf.html

django.middleware.csrf.CsrfViewMiddleware が有効になっている場合は、このように書きましょう。

5.タスク処理(改)

 [views.py]
 from django.views.decorators.csrf import csrf_exempt

 @csrf_exempt
 def task(request):
  … あれこれ
  return HttpResponse()

無事、解決。

2016年5月6日金曜日

GAE で、Django/Sitemaps を使う。

こちらの続きです。
http://yamayoshi.blogspot.jp/2016/05/gaep-django18-djangae.html
http://yamayoshi.blogspot.jp/2016/05/djangae-ndb.html

GAE のデータベース(NDB)は、Django のモデルを使えないので、当然、サイトマップフレームワーク(Sitemaps)も使えません。
でも、djangae によって、この問題を解決出来そうです。

こちらを参考に。
https://docs.djangoproject.com/en/1.8/ref/contrib/sitemaps/

1.概要
・設定ファイルにフレームワーク(SitesとSitemaps)を追加
・サイトマップクラスの作成
・URLディスパッチャーの設定
・サイトIDの生成
・設定ファイルに SITE_ID を追加
・サイトマップを確認

2.コード

2-1.設定ファイルにフレームワーク(SitesとSitemaps)を追加

$ cd ~/gae/project
$ nano mysite/settings.py
--
INSTALLED_APPS = (
 〜
 'home',
 'django.contrib.sites',  #追加
 'django.contrib.sitemaps', #追加
)
--

2-2.サイトマップクラスの作成 (新規)

$ nano home/sitemaps.py
--
# encoding: UTF-8
from django.contrib.sitemaps import Sitemap
from .models import *

class IndexSitemap(Sitemap):
 def items(self):
  return ['index']
 def location(self, obj):
  return '/'

class LinkSitemap(Sitemap):
 limit = 10
 def items(self):
  return Link.objects.all()
--

※ LinkSitemap クラスで、Link モデルからデータを読みだします。

2-3.URLディスパッチャーの設定

$ nano mysite/urls.py
--
# encoding: UTF-8
from django.conf.urls import include, url
from django.contrib import admin
from home import views
from django.contrib.sitemaps import views # Sitemapsのビュー
from home import sitemaps as hs

sitemaps = {
 'index': hs.IndexSitemap,
 'links': hs.LinkSitemap, # home/sitemaps の LinkSitemap クラス
}

urlpatterns = [
 url(r'^', include('home.urls')),
 url(r'^admin/', include(admin.site.urls)),
 url(r'^sitemap\.xml$', views.index, {'sitemaps': sitemaps}),
 url(r'^sitemap-(?P<section>.+)\.xml$', views.sitemap, {'sitemaps': sitemaps}),
]
--

3.サイトIDの生成

開発用サーバを起動
$ python ../google_appengine/dev_appserver.py ./

ブラウザで、adminページにアクセス
=> http://localhost:8080/admin/

サイトを登録
Site -> Add で、Domain name と Display name を入力 -> Save

SDK のコンソールにアクセス
=> http://localhost:8000/

Datastore Viewer -> Entity Kind「django_site」を選択 -> ListEntities

ID を確認します。

4.設定ファイルに サイトID を追加

$ nano mysite/settings.py
--
DEBUG = True
SITE_ID = xxxxxxxxxxxxxxxxxx #追加
--

5.サイトマップを確認

ブラウザで、サイトマップにアクセス
=> http://localhost:8080/sitemap.xml

6.所感

サイトマップフレームワークは、sitemap.xml をインデックスとして、複数のサイトマップを自動生成してくれます。
これが、本当にすばらしいと思います。

ちょっと悩んだのは、SITE_ID...
admin ページで入力して、SDK のコンソールで ID を確認するってのがミソ。
最初、なにげなく「1」と入れたら、アッサリとエラーで弾かれ.. 汗汗。

さて、動作確認は、ここまでとして、以前作ったものを Django1.8+djangae に移行したいと思います。

djangae で NDB にデータを格納する。

こちらの続きです。
http://yamayoshi.blogspot.jp/2016/05/gaep-django18-djangae.html

1.概要
・モデル(home/models.py)の定義
・URLディスパッチャーの設定(mysite/urls.py と home/urls.py)
・ビュー(home/views.py)を書く
・データを格納
・adminページでデータを確認

2.コードを書く

2-1.モデルの定義

こらを参考に。
https://docs.djangoproject.com/en/1.8/topics/db/models/

$ cd ~/gae/project
$ nano home/models.py
--
# encoding: UTF-8
from django.db import models
from django.utils.http import urlquote

class Link(models.Model):
 url   = models.CharField(max_length=200, primary_key=True)
 title = models.CharField(max_length=200)
 dt    = models.DateTimeField(auto_now=True)

 def get_absolute_url(self):
  return "/url/?" + self.url

 class Meta:
  ordering = ['-dt']
--

設定ファイルにモデル(の入っている場所)を追加

$ nano mysite/settings.py
--
INSTALLED_APPS = (
 〜
 'home', #追加
)
--

adminページでモデルを読み込めるように。

$ nano home/admin.py
--
# encoding: UTF-8
from django.contrib import admin
from .models import *

class LinkAdmin(admin.ModelAdmin):
 list_display = ('url', 'title', 'dt')

admin.site.register(Link, LinkAdmin)
--

2-2.URLディスパッチャーの設定

こちらを参考に。
https://docs.djangoproject.com/en/1.8/topics/http/urls/

まず、メインのディスパッチャー。

$ nano mysite/urls.py
--
# encoding: UTF-8
from django.conf.urls import include, url
from django.contrib import admin
from home import views

urlpatterns = [
 url(r'^', include('home.urls')),
 url(r'^admin/', include(admin.site.urls)),
]
--

続いて、アプリケーションのディスパッチャー。

$ nano home/urls.py
--
# encoding: UTF-8
from django.conf.urls import url
from . import views

urlpatterns = [
 url(r'^test/', views.test),
]
--

2-3.ビューを書く

こちらを参考に。
https://docs.djangoproject.com/en/1.8/topics/http/views/

$ nano home/views.py
--
# encoding: UTF-8
from django.http import *
from .models import *
from datetime import datetime

def test(request):

 for i in range(1, 100):
  res = datetime.now()
  link = Link(url=res, title=i)
  link.save()

 return HttpResponse(res)
--

3.データを格納

開発用サーバを起動
$ python ../google_appengine/dev_appserver.py ./

ブラウザで、testページにアクセス。しばらく待つ。
=> http://localhost:8080/test/

データの格納が完了すると、こんな表示が出ます。
 2016-05-06 01:07:42.358893

4.データを確認

ブラウザで、adminページにアクセスして、データを確認。
=> http://localhost:8080/admin/

 HOME -> Links に、いっぱい入ってます。

5.所感

とりあえず、Django のモデルで、データの格納が出来ました。
裏で NDB が動いてるので、なんらかの制限はありそうですが、普通に使えそうです。

次は、いよいよ、Sitemaps に挑戦!!
実は、これをやりたかったんだよね。

2016年5月4日水曜日

GAE/P + Django1.8 + djangae に挑戦!

一応、動作を確認できたので、忘れないうちに書き込んでおきます。

1.構成

こんなカンジで配置していきます。

gae/
├ google_appengine/ … GAE の SDK です。
├ venv/
│ └ … Django1.8 … プロジェクト作成用です。
└ project/
  ├ mysite/
  │ ├ settings.py
  │ ├ wsgi.py
  │ └ urls.py
  ├ home/
  ├ lib/ … GAE にアップロードするライブラリの置き場です。
  │ └ Django1.8, djangae,
  ├ appengine_config.py
  ├ app.yaml

2.SDK のインストール

こちらからダウンロードして解凍します。
https://cloud.google.com/appengine/downloads

$ cd
$ mkdir gae
$ cd ~/gae
$ wget https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.36.zip
$ unzip google_appengine_1.9.36.zip
$ rm google_appengine_1.9.36.zip

3.Django プロジェクトの作成

3-1.仮想環境にDjango1.8をインストールします。

$ cd ~/gae
$ virtualenv venv
$ source ~/gae/venv/bin/activate
V pip install django==1.8.7

3-2.仮想環境内に、プロジェクトとアプリケーションを作成します。

V django-admin.py startproject mysite
V mv mysite project
V cd project
V python manage.py startapp home

※ プロジェクト名(project)とアプリケーション名(home)は仮です。

4.ライブラリの追加

GAE にアップロードするライブラリを /lib にインストールします。

V cd ~/gae/project
V mkdir lib
V pip install -t lib Django==1.8.7 djangae
V deactivate

5.各種設定

$ cd ~/gae/project

5-1. mysite/settings.py (変更)

① 最初に、これ。

# encoding: UTF-8
from djangae.settings_base import *

② インストール・アプリケーション

INSTALLED_APPS = (
 'djangae', #1行目に追加
 〜
 'djangae.contrib.gauth.datastore', #最終行に追加 Google認証用
)

③ ミドルウェア

MIDDLEWARE_CLASSES = (
 'google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware', #1行目に追加 appstats用
 'djangae.contrib.security.middleware.AppEngineSecurityMiddleware', #追加
 〜
 #'django.contrib.auth.middleware.AuthenticationMiddleware', #コメントアウト
 'djangae.contrib.gauth.middleware.AuthenticationMiddleware', #追加 Google認証用
 〜
)

④ データーベース

DATABASES = {
 'default': {
  'ENGINE': 'djangae.db.backends.appengine',
 }
}

⑤ 最後に、これ。

from djangae.contrib.gauth.settings import *  # 最終行に追加

5-2. mysite/wsgi.py (変更)

--
# encoding: UTF-8
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
#application = get_wsgi_application()  #コメントアウト
from djangae.wsgi import DjangaeApplication #2行追加
application = DjangaeApplication(get_wsgi_application())
--

5-3. appengine_config.py (新規作成)

こちらを参考に。
http://d.hatena.ne.jp/noazoh/20140924/1411553513

--
# encoding: UTF-8
import os
import sys
import logging
BASE_DIR = os.path.dirname(__file__)
LIB_DIR = os.path.join(BASE_DIR, 'lib') #ライブラリの置き場所
sys.path.append(LIB_DIR)
sys.path.append(os.path.join(LIB_DIR, "dateutil"))
from google.appengine.ext import vendor
vendor.add('lib')
--

5-4. app.yaml (新規作成)

こちらを参考に。
https://cloud.google.com/appengine/docs/python/config/appref

--
application: myapp
version: alpha-001
runtime: python27
api_version: 1
threadsafe: true
builtins:
- appstats: on
handlers:
- url: /static/admin/
  static_dir: lib/django/contrib/admin/static/admin/
  secure: always
- url: /admin.*
  script: mysite.wsgi.application
  secure: always
  login: admin
- url: /.*
  script: mysite.wsgi.application
--

6.動作確認

$ cd ~/gae/project
$ python ../google_appengine/dev_appserver.py ./

ブラウザで確認します。
① http://localhost:8080  => おなじみの It worked! が表示されれば成功です。
② http://localhost:8080/admin/  => Django administration を使えます。
③ http://localhost:8080/_ah/stats/  => appstats を使えます。素晴らしい!!
④ http://localhost:8000  => SDK で コンソールも使えます。

7.所感など

なんとか、ここまでたどり着きました。
Web等で情報を探しても、なかなか見つからなかったけど、とりあえず、やりたいことは出来そうなカンジです。

引き続き、models とか、Sitemaps とか、試してみます。

8.おまけ

mysite/settings.py
--
# encoding: UTF-8

from djangae.settings_base import *

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '&c&k%d%s84me^(2i^hq7e$x6*b%93#wfn!n5kfjzn65+e4yw-5'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = (
'djangae',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#
'djangae.contrib.gauth.datastore',
)

MIDDLEWARE_CLASSES = (
'google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware',
'djangae.contrib.security.middleware.AppEngineSecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'djangae.contrib.gauth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
)

ROOT_URLCONF = 'mysite.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'mysite.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'djangae.db.backends.appengine',
}
}


# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_URL = '/static/'

from djangae.contrib.gauth.settings import *
--

djangae 勝手に日本語訳 - インストール

原文:
https://djangae.readthedocs.io/en/latest/installation/

Installation
ja> インストール

If you just want to get started on a fresh Django project, take a look at djangae-scaffold
ja> あなただけの新鮮なDjangoプロジェクトを始めたい場合は、djangae-scaffold を見て下さい。

Alternatively, you can also follow this guide:
ja> 代わりに、あなたはまた、このガイドに従うことができます。

1.Create a Django project, add app.yaml to the root. Make sure Django 1.7+ is in your project and importable
ja> Djangoプロジェクトを作成し、ルートディレクトリに app.yaml を追加します。Djangoの1.7以降は、プロジェクトにインポート可能であることを確認してください。

2.Install Djangae into your project, make sure it's importable (you'll likely need to manipulate the path in manage.py and wsgi.py)
ja> あなたのプロジェクトに Djangae をインストールし、インポート可能であることを確認してください。(あなたはおそらく manage.py と wsgi.py で、適切なパスを設定する必要があります。)

3.Add djangae to INSTALLED_APPS.
ja> settings.py の INSTALLED_APPS に djangae を追加します。

4.At the top of your settings.py, insert the following line to setup some default settings:
ja> settings.py の上部に、次の行を挿入します。

 from djangae.settings_base import *

In app.yaml add the following handlers:
ja> app.yaml に、以下のハンドラを追加します。

 * url: /_ah/(mapreduce|queue|warmup).*
  script: YOUR_DJANGO_APP.wsgi.application
  login: admin

 * url: /.*
  script: YOUR_DJANGO_APP.wsgi.application

Make your manage.py look something like this:
ja> このようなかんじで、manage.py を作ります。

 if __name__ == "__main__":
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
  from djangae.core.management import execute_from_command_line
  execute_from_command_line(sys.argv)

Use the Djangae WSGI handler in your wsgi.py, something like
ja> wsgi.py に、djangae WSGIハンドラを適用します。

 from django.core.wsgi import get_wsgi_application
 from djangae.wsgi import DjangaeApplication
 application = DjangaeApplication(get_wsgi_application())

Add the following to your URL handler:
ja> (urls.pyの)URLハンドラに以下を追加します。

 url(r'^_ah/', include('djangae.urls'))

It is recommended that for improved security you add
djangae.contrib.security.middleware.AppEngineSecurityMiddleware as the first of your middleware classes. This middleware patches a number of insecure parts of the Python and App Engine libraries and warns if your Django settings aren't as secure as they could be.
ja> セキュリティの向上のために、あなたのミドルウェアクラスの最初に、djangae.contrib.security.middleware.AppEngineSecurityMiddleware を追加することをお勧めします。本ミドルウェアは、PythonとApp Engineのライブラリの安全でない部品をパッチし、安全でない場合は警告を表示します。

If you wish to use the App Engine's Google Accounts-based authentication to authenticate your users, and/or you wish to use Django's permissions system with the Datastore as you DB, then see the section on Authentication.
ja> ユーザーを認証するために App Engine の Googleアカウントベースの認証を使用する場合、または、DBなどのデータストアでDjangoの権限システムを使用したい場合は、認証のセクションを参照してください。

It is highly recommended that you read the section on Unique Constraints
ja> Unique Constraints のセクションを読むことを強くお勧めします。

GAE vs VPS

Django を使うには、GAE or VPS どちらが良いのだろう??

GAE(Google App Engine)の良い所
・(ある程度)無料で使える。
・開発環境(SDK)が用意されている。
・ストレージやタスクキューが標準で準備されている。
・(お金を出せば)オートスケールできる。
・appstats 超ヤバイ!!

VPS(Virtual Private Server)の良い所。
・OSやライブラリーを自由に選択できる。
・Djangoの全ての機能を使うことができる。

と、どちらも一長一短。

最近、ABLENET の VPS で Django1.8 を使い始めたのだが、環境を作るのが、やっぱ大変なんだよね。
で、GAE で Django1.8 を使えないか探してたら、djangae を見つけた。

djangae は GAE の NDB を Django の models として使えるみたい。おぉ〜これすごいかも。
これで、admin も Sitemaps を使えるぞ。

と言うことで、しばらく GAE/P + Django1.8 + djangae でやってみよう。
続きは、おぃおぃと。

2016年5月3日火曜日

Djangae(じゃんじー)とは。

まだ、調査中ですが、これ、よさそうです。

本家:
https://djangae.readthedocs.io

この一文が、本気。
The best way to run Django on Google App Engine.

訳:
「Djangae(じゃんじー)」は、GAE(Google App Engine)で、Djangoを使う、最高の方法(Best Way)です。

概要ですが、これも、良いねぇ。
Djangae (jan-gee) is a Django app that allows you to run Django applications on Google App Engine, including (if you want to) using Django's models with the App Engine Datastore as the underlying database.

超訳:
 GAEでDjangoを使うなら、Djandaeをインストールしろ!!!!!!!!!!!!!!!!!!!!!

いじょう。
(もう少し、調べてみます。)