入门指南 #################### Hello, world! ================== 首先我们以一个简单的 hello world 应用介绍一下一个 Python 应用在新浪云上的创建和部署过程。 创建应用 ----------- 登录新浪云,进入 `我的首页`_ ,点击 `创建新应用` ,创建一个新的应用 helloworld。运行环境选择 *Python2.7* 。 .. _我的首页: http://sae.sina.com.cn/?m=apps&a=create 编辑应用代码 --------------- 首先,创建一个 *helloworld* 目录作为应用的代码目录,进入 *helloworld* 目录。 .. code-block:: console jaime@westeros:~$ mkdir helloworld jaime@westeros:~$ cd helloworld 在目录下创建应用配置文件 *config.yaml* ,内容如下: .. code-block:: yaml name: helloworld version: 1 创建应用的代码入口文件 *index.wsgi* ,内容如下: .. code-block:: python import sae def app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ['Hello, world!'] application = sae.create_wsgi_app(app) 新浪云上的 Python 应用的入口为 `index.wsgi:application` ,也就是 `index.wsgi` 这个文件中名为 `application` 的 callable object。在 helloworld 应用中,该 application 为一个 wsgi callable object。 部署应用 --------------- 我们选择 Git 作为部署工具。 首先,创建一个 Git 代码仓库,将刚才的代码提交到 Git 仓库中。 .. code-block:: console jaime@westeros:~/helloworld$ git init jaime@westeros:~/helloworld$ git add . jaime@westeros:~/helloworld$ git commit -m 'Initial commit' 然后,添加一个新的 Git 远程仓库 sae,地址为: https://git.sinacloud.com/ 应用名 ,然后将刚才提交的代码推到远程 Git 仓库的分支 1 中。 .. code-block:: console jaime@westeros:~/helloworld$ git remote add sae https://git.sinacloud.com/helloworld jaime@westeros:~/helloworld$ git push sae master:1 至此,整个代码的部署就完成了,在浏览器中输入 `http://helloworld.sinaapp.com` ,就可以访问刚提交的应用了。 使用 web 开发框架 ==================== Django ---------- 目前新浪云 Python 运行环境中预置了多个版本的 Django,默认的版本为 1.2.7,在本示例中我们使用 1.4 版本。 创建一个 Django project:mysite。 .. code-block:: console jaime@westeros:~/pythondemo$ django-admin.py startproject mysite jaime@westeros:~/pythondemo$ ls mysite manage.py mysite/ 创建应用配置文件 `config.yaml` ,在其中添加如下内容: .. code-block:: yaml libraries: - name: "django" version: "1.4" 创建文件 index.wsgi,内容如下 .. code-block:: python import sae from mysite import wsgi application = sae.create_wsgi_app(wsgi.application) 最终目录结构如下 .. code-block:: console jaime@westeros:~/pythondemo$ ls config.yaml index.wsgi manage.py mysite/ jaime@westeros:~/pythondemo/1$ ls mysite __init__.py settings.py urls.py views.py 部署代码,访问 `http://.sinaapp.com` ,就可看到 Django 的欢迎页面了。 `完整示例`_ ( `django tutorial`_ 中的 poll、choice 程序) .. _django tutorial: https://docs.djangoproject.com/en/1.4/intro/tutorial01/ .. _完整示例: https://github.com/sinacloud/sae-python-dev-guide/tree/master/examples/django/1.4 `django-1.2.7 示例`_ .. _django-1.2.7 示例: https://github.com/sinacloud/sae-python-dev-guide/tree/master/examples/django/1.2.7 处理用户上传文件 `````````````````` 在 setttings.py 中添加以下配置 .. code-block:: python # 修改上传时文件在内存中可以存放的最大 size 为 10m FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 新浪云的本地文件系统是只读的,修改 django 的 file storage backend 为 Storage DEFAULT_FILE_STORAGE = 'sae.ext.django.storage.backend.Storage' # 使用 media 这个 bucket STORAGE_BUCKET_NAME = 'media' # ref: https://docs.djangoproject.com/en/dev/topics/files/ 发送邮件 `````````` 在 settings.py 中添加以下配置,即可使用新浪云的 mail 服务来处理 django 的邮件发送了。 .. code-block:: python ADMINS = ( ('administrator', 'administrator@gmail.com'), ) # ref: https://docs.djangoproject.com/en/dev/ref/settings/#email EMAIL_BACKEND = 'sae.ext.django.mail.backend.EmailBackend' EMAIL_HOST = 'smtp.example.com' EMAIL_PORT = 587 EMAIL_HOST_USER = 'sender@gmail.com' EMAIL_HOST_PASSWORD = 'password' EMAIL_USE_TLS = True SERVER_EMAIL = DEFAULT_FROM_EMAIL = EMAIL_HOST_USER 数据库的主从读写 `````````````````` 参见 Django 官方文档 `Multiple databases`_ .. _Multiple databases: https://docs.djangoproject.com/en/1.2/topics/db/multi-db/#multiple-databases 如何 syncdb 到线上数据库 ```````````````````````` 在本地开发环境中,如下配置数据库,即可执行 `python manage.py syncdb` 直接 syncdb 到线上数据库。 .. code-block:: python # 线上数据库的配置 MYSQL_HOST = 'w.rdc.sae.sina.com.cn' MYSQL_PORT = '3307' MYSQL_USER = 'ACCESSKEY' MYSQL_PASS = 'SECRETKEY' MYSQL_DB = 'app_APP_NAME' from sae._restful_mysql import monkey monkey.patch() DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': MYSQL_DB, 'USER': MYSQL_USER, 'PASSWORD': MYSQL_PASS, 'HOST': MYSQL_HOST, 'PORT': MYSQL_PORT, } } .. warning:: 本 feature 还在开发中,目前还很 buggy。 如何 serve admin app 的静态文件 ````````````````````````````````` 方法一: 修改 `settings.py` 中的 `STATIC_ROOT` 为应用目录下 `static` 子目录的绝对路径。 运行 `python manage.py collectstatic` 将静态文件收集到应用的 `static` 子目录下。 修改 `config.yaml` ,添加对 static 文件夹下的静态文件的 handlers。 .. code-block:: yaml handlers: - url: /static static_dir: path/to/mysite/static 方法二: 在开发调试(settings.py 中 DEBUG=True)过程中,可以将 `staticfiles_urlpatterns`_ 加到你的 URLConf,让 Django 来处理 admin app 的静态文件: .. code-block:: python # urls.py from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', #... # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), ) from django.contrib.staticfiles.urls import staticfiles_urlpatterns urlpatterns += staticfiles_urlpatterns() 由于新浪云默认 static 为静态文件目录,需要修改 config.yaml,添加任意一条规则覆盖默认行为。 .. code-block:: yaml # config.yaml handlers: - url: /foo static_dir: foo ref: https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/ https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/modwsgi/#serving-the-admin-files .. _staticfiles_urlpatterns: https://docs.djangoproject.com/en/dev/howto/static-files/#staticfiles-development Flask ------------ index.wsgi :: import sae from myapp import app application = sae.create_wsgi_app(app) myapp.py :: import MySQLdb from flask import Flask, g, request app = Flask(__name__) app.debug = True from sae.const import (MYSQL_HOST, MYSQL_HOST_S, MYSQL_PORT, MYSQL_USER, MYSQL_PASS, MYSQL_DB ) @app.before_request def before_request(): g.db = MySQLdb.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, port=int(MYSQL_PORT)) @app.teardown_request def teardown_request(exception): if hasattr(g, 'db'): g.db.close() @app.route('/') def hello(): return "Hello, world! - Flask" @app.route('/demo', methods=['GET', 'POST']) def greeting(): html = '' if request.method == 'POST': c = g.db.cursor() c.execute("insert into demo(text) values(%s)", (request.form['text'])) html += """
""" c = g.db.cursor() c.execute('select * from demo') msgs = list(c.fetchall()) msgs.reverse() for row in msgs: html += '

' + row[-1] + '

' return html Bottle ---------- index.wsgi :: from bottle import Bottle, run import sae app = Bottle() @app.route('/') def hello(): return "Hello, world! - Bottle" application = sae.create_wsgi_app(app) web.py --------- index.wsgi :: import os import sae import web urls = ( '/', 'Hello' ) app_root = os.path.dirname(__file__) templates_root = os.path.join(app_root, 'templates') render = web.template.render(templates_root) class Hello: def GET(self): return render.hello() app = web.application(urls, globals()).wsgifunc() application = sae.create_wsgi_app(app) Tornado ------------ index.wsgi :: import tornado.wsgi import sae class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world! - Tornado") app = tornado.wsgi.WSGIApplication([ (r"/", MainHandler), ]) application = sae.create_wsgi_app(app) .. tip:: 以上所有的示例代码的完整版本都可以在我们的 github repo 中获得。 https://github.com/sinacloud/sae-python-dev-guide/tree/master/examples/