入门指南¶
Hello, world!¶
首先我们以一个简单的 hello world 应用介绍一下一个 Python 应用在新浪云上的创建和部署过程。
编辑应用代码¶
首先,创建一个 helloworld 目录作为应用的代码目录,进入 helloworld 目录。
jaime@westeros:~$ mkdir helloworld
jaime@westeros:~$ cd helloworld
在目录下创建应用配置文件 config.yaml ,内容如下:
name: helloworld
version: 1
创建应用的代码入口文件 index.wsgi ,内容如下:
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 仓库中。
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 中。
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。
jaime@westeros:~/pythondemo$ django-admin.py startproject mysite
jaime@westeros:~/pythondemo$ ls mysite
manage.py mysite/
创建应用配置文件 config.yaml ,在其中添加如下内容:
libraries:
- name: "django"
version: "1.4"
创建文件 index.wsgi,内容如下
import sae
from mysite import wsgi
application = sae.create_wsgi_app(wsgi.application)
最终目录结构如下
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://<your-application-name>.sinaapp.com ,就可看到 Django 的欢迎页面了。
完整示例 ( django tutorial 中的 poll、choice 程序)
处理用户上传文件¶
在 setttings.py 中添加以下配置
# 修改上传时文件在内存中可以存放的最大 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 的邮件发送了。
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
如何 syncdb 到线上数据库¶
在本地开发环境中,如下配置数据库,即可执行 python manage.py syncdb 直接 syncdb 到线上数据库。
# 线上数据库的配置
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,
}
}
警告
本 feature 还在开发中,目前还很 buggy。
如何 serve admin app 的静态文件¶
方法一:
修改 settings.py 中的 STATIC_ROOT 为应用目录下 static 子目录的绝对路径。
运行 python manage.py collectstatic 将静态文件收集到应用的 static 子目录下。
修改 config.yaml ,添加对 static 文件夹下的静态文件的 handlers。
handlers:
- url: /static
static_dir: path/to/mysite/static
方法二:
在开发调试(settings.py 中 DEBUG=True)过程中,可以将 staticfiles_urlpatterns 加到你的 URLConf,让 Django 来处理 admin app 的静态文件:
# 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,添加任意一条规则覆盖默认行为。
# 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
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 += """
<form action="" method="post">
<div><textarea cols="40" name="text"></textarea></div>
<div><input type="submit" /></div>
</form>
"""
c = g.db.cursor()
c.execute('select * from demo')
msgs = list(c.fetchall())
msgs.reverse()
for row in msgs:
html += '<p>' + row[-1] + '</p>'
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)
小技巧
以上所有的示例代码的完整版本都可以在我们的 github repo 中获得。 https://github.com/sinacloud/sae-python-dev-guide/tree/master/examples/