Category Archives: python

SAE python入门教程(3)- 框架的使用

SAE 预装支持以下几个框架

如果你经常使用以上框架的一种,那么你就可以很轻松的使用了,如果你使用的框架不在以上的行列中,那么请自行上传import使用。下面就从其中一个框架django出发讲叙怎么在sae的python环境下使用预装的框架进行快速的开发。
SAE上预装了两个版本的django,版本分别为1.2.7和1.4,默认的版本为1.2.7,那么怎么区分这两个版本呢?这时候config.yaml就起到关键性的作用了,svn co 出代码后,找到config.yaml文件,编辑为:

---
name: quixote
version: 6
libraries:
- name: "django"
  version: "1.4"

此时就引入了django 1.4了,修改版本号version 为1.2.7就会引入版本1.2.7。首先创建一个django的默认配置文件 setting.py

# Django settings for mysite project.

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@example.com'),
)

MANAGERS = ADMINS

import os

if 'SERVER_SOFTWARE' in os.environ:
    from sae.const import (
        MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASS, MYSQL_DB
    )
else:
    # Make `python manage.py syncdb` works happy!
    MYSQL_HOST = 'localhost'
    MYSQL_PORT = '3306'
    MYSQL_USER = 'root'
    MYSQL_PASS = 'root'
    MYSQL_DB   = 'app_pylabs'

DATABASES = {
    'default': {
        'ENGINE':   'django.db.backends.mysql',
        'NAME':     MYSQL_DB,
        'USER':     MYSQL_USER,
        'PASSWORD': MYSQL_PASS,
        'HOST':     MYSQL_HOST,
        'PORT':     MYSQL_PORT,
    }
}

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True

# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'up)24f2-l-+#g7ek4hp8ri1ng$@nbwqk+(fhdshgn9sc#b*oyl'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'urls'

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'wsgi.application'

import os.path

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(os.path.dirname(__file__), 'templates'),
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

注意:这里的

ROOT_URLCONF = ‘urls’
# Python dotted path to the WSGI application used by Django’s runserver.
WSGI_APPLICATION = ‘wsgi.application’

说明我们的url所有的路由都是从urls.py出发的,程序的起点在wsgi.application 这个application就是一个创建了一个wsgi.首先配置urls.py文件如下:

from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    url(r'^$', 'test.current_datetime'),
    # url(r'^mysite/', include('mysite.foo.urls')),

)

# Serve static files for admin, use this for debug usage only
# `python manage.py collectstatic` is preferred.
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()

注意url(r’^$’, ‘test.current_datetime’), 表示我们将所有的根目录的请求都路由到test.py下面的current_datetime函数~ 那么我们来写一个简单的函数:配置test.py

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

嘿嘿,就默认的输出当前的时间吧~那么最后还有一个wsgi文件,如下:

# -*- coding: utf-8 -*-
import os
from settings import *
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from django.core.wsgi import get_wsgi_application
from test import current_datetime
application = get_wsgi_application()

万事具备,只欠首页了,再看看此时的index.wsgi文件

import sae
import wsgi

application = sae.create_wsgi_app(wsgi.application)

很简单的,只是导入wsgi.py,创建一个application,其他的都是根据urls.py来找对应的函数去执行就是了~此时访问下我们的页面http://6.quixote.sinaapp.com/

那个剩余的开发就是不停的添加函数,在urls.py指定路由了。

本实例的代码打包下载:

http://quixote-test.stor.sinaapp.com/sae_djnago_demo.zip

你可以从 http://quixote-test.stor.sinaapp.com/saepythondevguide-master.zip 下载所有的SAE python环境下的所有框架的demo实例,其中还包含了一些服务例如分词接口,新浪微博接入等例子,很实用。

这些实例的原链接是:https://github.com/SAEPython/saepythondevguide/downloads

SAE python入门教程(2)-相关服务使用以及调试

上文中讲到了sae的初步使用以及sae python环境的相关资料,如果你不了解这些知识,你可以点击 http://skirt.sinaapp.com/?p=392 查看。那么从本文开始,我们将开始介绍如何在sae的python环境下使用sae提供的几大服务,其中包括文件存取服务storage,内存缓存memcache,网页抓取fetchurl,邮件服务等等。

操作storage

在sae使用storage服务,首先,我们需要在sae的管理面板创建一个storage的domain,如下图所示,我们点击创建一个domain,例如应用名test,那么创建完我们就可以用python脚本来管理它了。

在上一篇文章中,我们接触了hello wolrd,那么在本次教程中我们将继续延伸上次的脚本,我们创建一个操作storage的脚本storage.py,在其中将一个演示的操作封装为一个函数storage,脚本的内容如下:

# -*- coding: utf-8 -*-
import sae.storage
def storage():
        # 初始化一个Storage客户端。
        s = sae.storage.Client()
        # PUT object至某个domain下面,put操作返回object的public url。
        ob = sae.storage.Object('hello lazy')
        s.put('test', 'lazy', ob)
        # GET某个domain下的object
        ob = s.get('test', 'lazy')
        data = ob.data
        # 获取object的public url
        url = s.url('test', 'lazy')
        return url

注意,这里的文件编码一定要指定,# -*- coding: utf-8 -*- 这个很重要,不然会报错。我们使用的domain name是 test,可以参见以上为test的部分,操作的api请参考http://appstack.sinaapp.com/static/doc/release/testing/service.html#storage
那么在index.wsgi中调用这个脚本,调用的方式如下:

import sae
from storage import storage
def app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    result = storage()
    print(result)
    return ['Hello, world!']

application = sae.create_wsgi_app(app)

注意,此时我们通过from storage import storage 引入了我们刚刚封装的storage,在app函数中执行了一次storage函数,并将得到的结果print了出来,那么是不是刷新应用就能看到打出的信息呢?经验告诉我们这里的print并不能将信息打到屏幕上,而是作为sae python的调试信息存起来了。我们登陆sae的管理面板,找到对应应用的日志中心,选择分类为“debug”此时我们可以看到:

显然我们已经成功的上传并得到了上传文件的绝对地址。那么关于删除,修改属性等等大家可以自己按照相应的方式操作下~

操作memcache

想要使用 sae 的memcache 服务,首先需要在sae的管理面板上开始memcache 服务,具体开启的大小可以按照你的需要来。一般推荐不需要超过20M,我这里只是提供教学,只开启了1M,根据文档介绍,SAE Python使用 http://sendapatch.se/projects/pylibmc/ 作为mc客户端。 不同之处在于,创建Client时不用指定servers。也就是说是在调用的时候,sae已经帮我们创建了连接,具体代码如下:

# -*- coding: utf-8 -*-
import pylibmc
def memcachess():
        mc = pylibmc.Client()
        mc.set("sae", "sae is great")
        value = mc.get("sae")
        return value

我们在index.wsgi 中稍微修改下代码使用下我们封装的memcache操作函数,具体可以如下:

import sae
#from storage import storage
from memcache import memcachess
def app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    #result = storage()
    result = memcachess()
    print(result)
    return ["%s" % result]

application = sae.create_wsgi_app(app)

注意此时我们直接将result的结果打在了屏幕上了,更方便调试,那么此时屏幕上不应该显示hello world了,而应该显示 sae is great,我们访问下此时的应用:

哈,操作memcache成功了。

操作Mysql

mysql作为一种最常用的存取服务了,那么在sae python环境下怎么操作mysql呢。我们也采用上面的方式,用一个实例来操作创建在sae 上的数据。首先我们需要知道我们的mysql的连接主机,端口,等等信息,那么在sae python的环境下我们需要手工引入sae的相关常量信息:

import sae.const

其中以下就给出了数据库的连接信息:

sae.const.MYSQL_DB # 数据库名
sae.const.MYSQL_USER # 用户名
sae.const.MYSQL_PASS # 密码
sae.const.MYSQL_HOST # 主库域名(可读写)
sae.const.MYSQL_PORT # 端口,类型为,请根据框架要求自行转换为int
sae.const.MYSQL_HOST_S # 从库域名(只读)

SAE是支持MySQLdb的,那么在得到了数据库的连接信息之后我们就可以管理我们的数据库了,先到 SAE 的管理面板上激活你的python应用的mysql,在phpmyadmin中创建一个简单的表:

CREATE TABLE IF NOT EXISTS `hellosae` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `age` int(5) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

那么此时我们的mysql.py代码如下:

#!/usr/bin/python
import MySQLdb
import sae.const
MYSQL_DB = sae.const.MYSQL_DB
MYSQL_USER = sae.const.MYSQL_USER
MYSQL_PASS = sae.const.MYSQL_PASS
MYSQL_HOST_M = sae.const.MYSQL_HOST
MYSQL_HOST_S = sae.const.MYSQL_HOST_S
MYSQL_PORT = int(sae.const.MYSQL_PORT)

def mysql():
        connection = MySQLdb.connection(host=MYSQL_HOST_M,port=MYSQL_PORT,user=MYSQL_USER,passwd=MYSQL_PASS)
        connection.select_db(MYSQL_DB)
        connection.query("""select * from hellosae limit 2""")
        r = connection.store_result()
        result = r.fetch_row()
        return result

这其中有几个值得注意的问题,第一个就是mysql的端口问题,在MySQLdb的连接参数中,port必须是int型的,而sae返回的常量信息中port是字符串类型,所以需要进行强制类型转换。
我们在index.wsgi中修改下代码使用我们刚刚封装的mysql函数,代码如下:

import sae
#from storage import storage
#from memcache import memcachess
from mysql import mysql
def app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    #result = storage()
    result = mysql()
    #print(result)
    return ["%s" % result]

application = sae.create_wsgi_app(app)

那么此时我们再刷新我们的应用,可以看到输出是:

其中我在数据库插入了两条数据,如下:,

可以发现,此时我们已经成功的操作了Mysql,那么关于更多的 insert,update,replace,delete等操作请参考MySQLdb的官方文档:http://mysql-python.sourceforge.net/MySQLdb.html#mysqldb

发送Mail

本次最后介绍一个典型的服务,SAE 的mail 服务。关于mail服务的详细介绍请参考 http://appstack.sinaapp.com/static/doc/release/testing/service.html#mail 在这里我用一个实际的例子来演示邮件的发送。我们封装一个mail发送的函数,具体的代码如下:

# -*- coding: utf-8 -*-
from sae.mail import send_mail
def  send_mail_lazy():
        send_mail("webmaster@changes.com.cn", "Sae python send mail test", "Hello SAE python!",("smtp.sina.com.cn", 25, "oozhuming@sina.com", "你的密码", False))

此时小小的修改下index.wsgi使用mail

import sae
#from storage import storage
#from memcache import memcachess
#from mysql import mysql
from mail import send_mail_lazy
def app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    #result = storage()
    #result = mysql()
    result = send_mail_lazy()
    #print(result)
    return ["%s" % result]

application = sae.create_wsgi_app(app)

此时访问下应用 可以发现输出是一个None,原因是sae的mail发送是异步,所以没有返回值,要看邮件的调试信息可以到sae的管理面板中选择日志中心,选择mail,如下:

可以看到一封发送失败的邮件,刚才执行的脚本邮件已经发送成功了,

本次教程所有代码打包下载:

http://quixote-test.stor.sinaapp.com/sae_python_demo.zip

SAE python入门教程(1)-Hello world

SAE python 参考资料

关于Python

你不爱python谁爱python,你不对python好谁对python好。希望更多的人真正沉下心去开发。

几个SAE上比较程序的python项目源码下载地址:

下面开始使用sae python,如果你没有SAE账号,请参考http://skirt.sinaapp.com/?p=290 ,注意在创建应用的时候选择python,没有python邀请码?需要到这里 http://appstack.sinaapp.com/apply 排队了。

Hello world

先创建index.wsgi 文件,该文件是SAE 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)

SVN commit 代码,刷新你的应用,此时就可以看到 http://1.quixote.sinaapp.com/

Python 连接 Mysql

本文环境在centos 6.0下。首先需要确认你的环境有MySQLdb包。
可以输入

[root@mingming-dev python]# python
Python 2.6.6 (r266:84292, Dec  7 2011, 20:48:22)
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named MySQLdb
>>>
</module></stdin>

出现No module named MySQLdb,说明没有这个包,需要手工加入,下载可以使用

wget "http://lazypeople.sinaapp.com/python/MySQL-python-1.2.3.tar.gz"

Continue reading