Long polling
这两天在公司的项目里用了 Long polling,了解了它的实现原理,其实不像它的名字那么玄乎,只是 Ajax 和 HTTP 的类似小妙招的办法。
先解释一下 Long polling 是什么:
首先得说到传统的 Polling,Polling 是 Ajax 隔一段时间去抓取服务器上的数据,检查数据是否更新,但这样有很大问题,首先是每次请求会实用一个 HTTP request,对应的服务器就得建一个新的线程来处理这个 HTTP request,消耗网络流量、服务器资源不说,绝大多数情况下,数据短时间内是不会更新的,也就是说绝大多数的 Ajax 请求都只能无功而返。
而 Long polling 就是用来解决这个问题的。
它的核心是:
1. 做一个超时非常长的 Ajax 请求,并且在错误捕获代码里不断执行自己。2. CGI 部分接收到请求后在限定的时间内(Ajax 超时时间内)每隔一段时间(例如一秒)对数据库进行查询,可以使用 sleep 类似的方法。
3. 如果有新的数据则返回,如果即将到 Ajax 超时的时间则返回一个错误值,比如 404,这样那个非常长的 Ajax 请求会再发一个过来,继续查询。
这个办法的最大价值是有效减少了 HTTP 请求数,对服务器而言就不用开启新的线程去处理它,旧的线程如果不是因为超时,则只会在数据已经更新的情况下返回数据。可以节约大量资源,而且实时性更高。
目前,人人网的消息提示、Web 版阿里旺旺、新浪微博的新微博提示应该都是使用这种方法做的。
但这个办法对开发有
所以最好做好两套配置,一套用于产品环境的多线程环境,
我依然对那位在现有架构下想出这种办法的人表示钦佩。
这儿有范例代码,简单又实用:http://stackoverflow.com/questions/333664/simple-long-polling-example-code
Django 应用程序调试
这里要介绍的是,全面的 Django app 调试,从最简单的打印变量,到使用 Django 自带的 Debug Middleware 调试 SQL,最后到全面的 Django debug toolbar 的使用。
2. Django debug context processor[1](中级)
3. Django debug toolbar[2](更简单而强大。。。 -_-#)
这是最简单的办法,在启动了 django-admin runserver 后,可将变量打印到终端上,适用于临时性的排错,当然还有其它办法,只是我觉得这种办法最简单。
下面是简单范例。
from pprint import pprint from django.http import HttpResponse from myapp.core.models import Case def index(request, template = 'index.html'): c = Case.objects.select_related('author').get(pk = 100) pprint(str(c.query)) # 打印 C.objects.get(pk = 100) 调用的 SQL pprint(dict(c)) # 打印 C.objects.get(pk = 100) 的世纪内容。 return HttpResponse(c.__dict__)
二、Django debug context processor[1]
该 Middleware 主要用于调试 SQL 执行情况,能够将所有的数据库查询 SQL 及花费时间打印出来,但是它要求代码使用 RequestContext,普通的 Context 和 render_to_response() 便无法直接使用了,如果之前代码使用 Context 构建,可能需要重写这部分代码。
其实我推荐在开始编写代码的时候,就使用 django.views.generic.simple.direct_to_template 来渲染页面,像如下:
from django.views.generic.simple import direct_to_template def index(request, template = 'index.html'): ... return direct_to_template(request, template, { 'parameters': parameters, 'case': c, })
下面说安装和使用方法:
在 settings.py 的 'TEMPLATE_CONTEXT_PROCESSORS' 段中加入 'django.core.context_processors.debug',如下:
# RequestContext settings
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.request',
'django.core.context_processors.media',
'django.core.context_processors.debug',
'myapp.core.context_processors.processor',
...
)
在 settings.py 中加入 'INTERNAL_IPS',用于识别开发机地址,内容写入本机 IP 地址即可:
# Needed by django.core.context_processors.debug: # See http://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-debug INTERNAL_IPS = ('127.0.0.1', )
然后,在共享模板的开头(别告诉我你一个页面一个模板文件。。。),加入生成 SQL 列表的代码:
<body id="body"> {% if debug %} <div id="debug"> <p> {{ sql_queries|length }} Quer{{ sql_queries|pluralize:"y,ies" }} {% ifnotequal sql_queries|length 0 %} (<span style="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.display=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';">Show</span>) {% endifnotequal %} </p> <table id="debugQueryTable" style="display: none;"> <tr class="odd"> <td>#</td> <td>SQL</td> <td>Time</td> </tr> {% for query in sql_queries %} <tr class="{% cycle odd,even %}"> <td>{{ forloop.counter }}</td> <td>{{ query.sql|escape }}</td> <td>{{ query.time }}</td> </tr>{% endfor %} </table> </div> {% endif %} ... </body>
最终生成的效果是在页面顶部,增加了一个 XX Quueries 项,点击 (Show) 后如下:
Django debug toolbar 是我到目前为止见过的安装最简单,功能最强大的调试工具,它的主要特性有:
* 更加完善的 SQL 调试(比 Django debug processor 更加精准,Django debug contect processor 无法处理关系查询(Select related))
* 记录 CPU 使用时间(可惜没有针对代码级的 profile,希望未来的版本能增加这个功能)
* 完整记录 HTTP Headers 和 Request 请求
* 完整记录模板 Context 内容,包括 RequestContext 和直接传入的变量
* 记录 Signals
* python logging 模块的日志支持
安装也比较简单,可以使用 yum 直接安装,也从上面的地址下载后,直接使用 setuptools 通用的安装方法安装即可。
$ tar zxvf robhudson-django-debug-toolbar-7ba80e0.tar.gz $ cd robhudson-django-debug-toolbar-7ba80e0 $ python ./setup.py build $ sudo python ./setup.py install
如需确保安装正常,从 Python shell 里看看能否 import 即可,不出错,即安装正常:
$ python Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import debug_toolbar >>>
然后是配置你的 settings.py。
我的调试 settings.py 和在产品服务器上运行的是不一样的,我也建议最好将二者分开,因为 Django app 开启 Debug 后对性能损耗非常严重。
将下面红字加入你自己的 settings.py 文件:
MIDDLEWARE_CLASSES = ( ... 'debug_toolbar.middleware.DebugToolbarMiddleware', ) INSTALLED_APPS = ( ... 'debug_toolbar' ) TEMPLATE_DIRS = ( ... '/Library/Python/2.6/site-packages/django_debug_toolbar-0.8.3-py2.6.egg/debug_toolbar/templates/', #按需修改!指向 debug_toolbar 的模板目录。 ) DEBUG_TOOLBAR_PANELS = (
'debug_toolbar.panels.version.VersionDebugPanel',
'debug_toolbar.panels.timer.TimerDebugPanel',
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
'debug_toolbar.panels.headers.HeaderDebugPanel',
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'debug_toolbar.panels.template.TemplateDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel'
)
然后使用 django-admin.py runserver 启动测试服务器,下图是 Django debug toolbar 的 SQL 查询页面。
相关链接:
[1] http://www.djangosnippets.org/snippets/93/
[2] http://github.com/robhudson/django-debug-toolbar/downloads
Django 下的 Kerberos 登录
Kerberos 这种统一用户名和密码进行登录的方式在各大公司(尤其外企)内部应该都得到广泛应用,它以其安全、高效和易于管理等特性得到了很多系统管理员的喜爱。
目前网上对于 Kerberos 登录原理的描述都过于复杂,其实它的实现非常简单,当你向一个部署了 Kerberos 的应用服务器发起登录请求的时候,服务器会去 /etc/krb5.conf 里描述的 KDC 服务器用 Kerberos 协议发起一个登录请求,如果用户名密码验证通过,将会向服务器发一个票(Ticket),否则将会引出一个错误。然后服务器可以将票发给客户端,以后客户端就可以用这张票进行其它操作。与火车票和电影票一样,Kerberos 的票,也是有使用时间限制的,如果不经过特殊设置,这张票的超时时间大约是 6 个小时。
而在 Django 里使用 Kerberos 登录,有两种办法,一种是由 Django 直接向 KDC 验证密码,另一种是在 Apache 上使用 mod_auth_kerb 模块,由浏览器来处理登录请求。
这两种办法其实都是对 Django Auth Backend 的重载,所有的 Auth Backend 都位于 django/contrib/auth/backends.py 里,这里[2]也有一个使用 Email 来进行验证的范例,我受此启发,写了这两个例子,希望也能抛砖引玉,能给你们更多启发。
第一种 - 由 Django 直接向 KDC 验证密码:
这种办法比较简单,需要在 web server 上装好 python-kerberos 包,并且配置好 /etc/krb5.conf,详细的配置方法,最好咨询 IT 部门,配置成功后在服务器上用 Kerberos 上有的普通用户运行 kinit,如果能够密码验证通过就行。
并且在 Django 的 settings.py 里写入类似下面这行,定义 Kerberos 的 Realm:
# Kerberos settings KRB5_REALM = 'EXAMPLE.COM'
与上面的 Email 验证例子类似的是,我们需要对 authenticate 方法进行重载,加入 kerberos 认证代码,python-kerberos 已经提供了 checkPassword 方法。
try: auth = kerberos.checkPassword( username, password, '', settings.KRB5_REALM ) except kerberos.BasicAuthError, e: return None
完整代码如下:
import kerberos from django.conf import settings from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import User class KerberosBackend(ModelBackend): """ Kerberos authorization backend for TCMS. Required python-kerberos backend, correct /etc/krb5.conf file, And correct KRB5_REALM settings in settings.py. Example in settings.py: # Kerberos settings KRB5_REALM = 'EXAMPLE.COM' """ def authenticate(self, username=None, password=None): try: auth = kerberos.checkPassword( username, password, '', settings.KRB5_REALM ) except kerberos.BasicAuthError, e: return None try: user = User.objects.get(username=username) except User.DoesNotExist: user = User.objects.create_user( username = username, email = '%s@%s' % (username, settings.KRB5_REALM.lower()) ) user.set_unusable_password() user.save() return user
第二种:Apache 上使用 mod_auth_kerb:
这种方法略有复杂,部署它需要向 KDC 申请一个 keytab 文件,以授权该 Web Server 向 KDC 发起请求,并且需要安装和配置 mod_auth_kerb(很简单,后面有),并且 /etc/krb5.conf 一点也不能少。
但是好处也是非常明显的,上面那种依然是使用 Django Auth Contrib 的 Session Manager 来负责登录信息的维持,但是这种方法将能够完全使用 Kerberos 自身提供的 Features,包括登录维持,和 kinit 的支持,也就是说,只要在本机上使用 kinit 成功登录过一次,用 Firefox (目前似乎在 Linux 上只支持该浏览器)访问部署了 mod_auth_kerb 的网站,将都不再需要登录。
它的原理包括两种条件,一种是没有在本机执行 kinit 的,使用 Firefox 直接访问服务器,服务器将会返回一个 401 Authorization Required 错误,这时 Firefox 会弹出对话框询问你的 Kerberos 用户名和密码,并提交你的密码。另一种在本机已经执行过 kinit 的,Firefox 会去读取你客户端的 Kerberos ticket 缓存,如果没有过期的话,就会使用它。无论哪种办法,Firefox 都将在 HTTP Header 里添加一个 'Authorization' 段,并且加入 Basic Authorization 验证方式,例如我本机上的:
Authorization Basic eGt1YW5nOkxvdmVvZnJvYWQuMTIz
使用这种部署方式,在 Django 1.1 版本以下,还没有比较好的解决办法,但好在 Django 1.1 提供了 RemoteUserBackend 后端,依然在 django/contrib/auth/backends.py 路径里,通过阅读它的代码,我们可以看到它其实依然是个 ModelBackend 的继承,而 Django 的 Request Handler 已经默认将 HTTP Meta 里的 REMOTE_USER 段给加入处理范围之内了,因此 RemoteUserBackend 的 ’authenticate‘ 与 ModelBackend 不太一样。 :-)
其实代码都已经写好,我们只需要处理一下拿到用户后的处理办法('configure_user' 方法)和处理用户名的方法('clean_username' 方法)就可以了。
我这里在拿到用户后,出于保护密码的原则,为该用户设置了一个无效密码('user.set_unusable_password()' 方法),并且设置了该用户的 Email。 同时,因为 RemoteUserBackend 默认返回的用户名是 ‘[username]@[KRB5_REALM]',所以我也把后面的 REALM 给去掉,直接贴代码:
from django.conf import settings from django.contrib.auth.backends import RemoteUserBackend class ModAuthKerbBackend(RemoteUserBackend): """ mod_auth_kerb modules authorization backend for TCMS. Based on DjangoRemoteUser backend. Required correct /etc/krb5.conf, /etc/krb5.keytab and Correct mod_auth_krb5 module settings for apache. Example apache settings: # Set a httpd config to protect krb5login page with kerberos. # You need to have mod_auth_kerb installed to use kerberos auth. # Httpd config /etc/httpd/conf.d/<project>.conf should look like this: <Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE <project>.settings PythonDebug On </Location> <Location "/auth/krb5login"> AuthType Kerberos AuthName "<project> Kerberos Authentication" KrbMethodNegotiate on KrbMethodK5Passwd off KrbServiceName HTTP KrbAuthRealms EXAMPLE.COM Krb5Keytab /etc/httpd/conf/http.<hostname>.keytab KrbSaveCredentials off Require valid-user </Location> """ def configure_user(self, user): """ Configures a user after creation and returns the updated user. By default, returns the user unmodified. Here, the user will changed to a unusable password and set the email. """ user.email = user.username + '@' + settings.KRB5_REALM.lower() user.set_unusable_password() user.save() return user def clean_username(self, username): """ Performs any cleaning on the "username" prior to using it to get or create the user object. Returns the cleaned username. For more info, reference clean_username function in django/auth/backends.py """ return username.replace('@' + settings.KRB5_REALM, '')
Django 是一个很强大的框架,虽然缺点和优点都同样的明显,有些甚至是由于 Python 语言或者类库造成的问题,但是因为其使用的便利性,高效的开发,而且其开发小组也非常活跃,使其特性的添加非常频繁,而且网上也有大量资源,例如 Django Snippets 网站,因此依然有着非常巨大优势。而通过阅读它的代码,往往都能获得更多启发。
链接:
十月总结
到月末了,对这两个月做一下总结。
首先是 VirtLAB,这个从三月开始的自动化测试项目,该项目用于在 QE 团队内部替代 RHTS,由于是重新设计的 Database schema,所以我可以充分发挥 Django 自身的优势,也是因为通过 VirtLAB,使我的 Django 水平得到了极大提高,同时由于 UI 前端是自己编写的,所以对 Javascript 也远远胜过之前。现在无论是 Django 本身的 ORM,Template,Form 都很难难到我了,自定义 ORM model field、Form 的 RequestContext Processor,Field 和 Template 的 Tag、Filter 也都得心应手。
在这两个月里,VirtLAB 发展到了 2.0,主要是增加了 Queue,用于在一台机器上建立一个 Job 队列,可以同时在一台机器上排上多个 Job,一个一个重启电脑,重装系统后执行测试脚本的特性;另一个就是晚上趁着没人的时候,自动根据数据库覆盖率(在哪些机器上运行过),跑测试的功能,所以界面也换成了夜间的风格。
新版本极大地提高了自动化功能,由测试人员编写好测试脚本,白天可以由测试人员自己提交 Job 在不同的机器上执行并实时观测运行过程,晚上下班后程序也会将那些在一些机器上没有跑过的测试执行一遍,最终做到每一个测试脚本在所有的机器上都执行一遍,以检查系统是否能够在不同类型的机器上稳定运行。
另一个是用于手动测试的 TCMS(与 Testopia database schema 完全兼容的 Test Case Management System),半年前将它撂下,现在又重新捡起来了,经过 VirtLAB 的磨砺,而且新版本里可以加表,所以我对这个代码进行了重构,使用了大量 Django 自身的特性,比如 ACL 和自带的 Admin Page。和 VirtLAB 一样,使用了 python-kerberos 做了个 Kerberos 的用户名密码验证。因为 Testopia 的数据表结构比较复杂,所以对整个 Models 进行了重构,用 ForeignKey 和 ManyToManyField 重新进行了组织,自行编写了 TimeAsTimeDeltaField 来处理 Test Case 的 Estimated Time。
UI 也经过丹青的重新设计,变得更加的方便、易用。
总之,是个脱胎换骨的版本。
明天,30 号就是正式内部使用的日子,svn 的版本号也相当吉利 2046。我们将正式用它来代替服役了很长时间的 Test Runner 和根本不成熟且有版权问题的 Testopia。
下一步计划 - 更加地自动化:
VirtLAB 将对每台机器加上 Tag,以后选机器不用去看主机名了,只要选好自己需要的配制,比如要 Intel 的处理器啊,要超过 4G 内存啊,就可以自动根据所选条件,自动选择空闲的机器,最快速地完成需要完成的 Job。
TCMS 将进一步对代码进行重构,进一步 Django app 化,同时完成 Report,以及和外部程序沟通的功能,目前只能将 Failed 的 Case 用 File a bug 链接直接提交到 Bugzilla 上,下一步将和 VirtLAB 和 ATP 整合,直接在 TCMS 里操作 VirtLAB 里的测试脚本。
BTW: 前一端时间公司内部开始使用 Redmine 进行内部项目管理,这个用 Rails 编写的工具确实有很多独到的特性,可以看看。
Django 的 Form 真的很好用。
Django 的 Form 表单真的很好用,完全把以往繁琐的表单操作完全抽象出来,成了一个独立的组件。
该系统的最大特色就是与模板无关,表单元素完全在一个文件里就可以定义好,以后也可以随时扩充,修改,很方便。
为了使用富文本编辑器我还使用了 InPlaceEditor,之所以用它是因为它基于强大的 TinyMCE 编辑器,同时提供了很好的 Ajax 支持,为了使用它我还使用了 django-tinymce,这个东西理论上应该找不到编译好的包,可以用 easy_install 安装(在 Fedora 10 里的 python-setuptools-devel 包里),总之就是怎么方便怎么来啦。 :-)
OK, Let's get start it.
在 app 目录里建立一个 forms 的目录,touch 一个 __init__.py,然后在其中写下 newapp.py 文件,如下内容:
from django import forms from tinymce.widgets import TinyMCE TYPE_CHOICES = [ [1, 'Desktop Computer'], [2, 'Laptop'], ] class NewProduct(forms.Form): name = forms.CharField() type_id = forms.ChoiceField(choices=TYPE_CHOICES) description = forms.CharField(widget=TinyMCE(mce_attrs={})
添加 View 里某个方法(比如 index)填上:
def index(request): from testproject.app.forms.newapp import NewProduct new_form = NewProduct() return render_to_response('testform.html', { 'new_form' : new_form })
然后改模板,类似如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.01//EN"> <html lang="en"> <head> <title>New Product</title> </head> <body> <h1>New Product</h1> <form action="." method="POST"> {{ new_form.as_table }} <p><input type="submit" value="Submit"></p> </form> </body> </html>
够好用吧?一个 form 定义好以后直接使用 as_table 方法就可以转换成表格。
如果需要更多自定义参数,也可以像访问数据库一样直接调用 form class 里的属性,如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.01//EN"> <html lang="en"> <head> <title>New Product</title> </head> <body> <h1>New Product</h1> <form action="." method="POST"> {{ new_form.name }} {{ new_form.type_id }} {{ new_form.description }} <p><input type="submit" value="Submit"></p> </form> </body> </html>
在 Django 的官方教程里,设计一个 form class 的 ChoiceField 使用的是 Tuple,而我这里经过试验,List 也是可以的,而之所以使用 List,是因为这样可以通过数据库,向 ChoiceField 里添加数据,如:
from django import forms from tinymce.widgets import TinyMCE from testproject.app.models import ProductTypes types = ProductTypes.objects.all() TYPE_CHOICES = [] for type in types: TYPE_CHOICES.append([type.id, type.name]) class NewProduct(forms.Form): name = forms.CharField() type_id = forms.ChoiceField(choices=TYPE_CHOICES) description = forms.CharField(widget=TinyMCE(mce_attrs={})
嘿嘿,基本到此,还是比较简单的,附带一个我的 TinyMCE 的设置作为结尾好了。
from django import forms from tinymce.widgets import TinyMCE from testproject.app.models import ProductTypes types = ProductTypes.objects.all() TYPE_CHOICES = [] for type in types: TYPE_CHOICES.append([type.id, type.name]) class NewProduct(forms.Form): name = forms.CharField() type_id = forms.ChoiceField(choices=TYPE_CHOICES) description = forms.CharField(widget=TinyMCE(mce_attrs={'theme' : "advanced", 'skin' : "o2k7", 'skin_variant' : "silver", 'elements' : 'elm3', 'mode' : 'textareas', 'theme_advanced_toolbar_location' : "top", 'theme_advanced_toolbar_align' : "left", 'theme_advanced_resizing' : 'true', 'plugins' : "safari,pagebreak,style,layer,save,iespell,xhtmlxtras", 'theme_advanced_buttons1' : "fontselect,fontsizeselect,|,cut,copy,paste,pastetext,|,bullist,numlist,|,undo,redo,|,link,unlink", 'theme_advanced_buttons2' : "", 'theme_advanced_buttons3' : "", })
不知道 Rails 或者其它 Web Framework 是否也有比较优秀的特色功能,希望也能有人能够介绍一下。
一个 Django 的超简单的数据库应用
昨天 Launch & Learn 的时候,做了个简单的 Django 的数据库应用,以配合 Li Li Zhang 的 ORM Course。
其实用 Django 做数据库应用真的很简单,不过比较适合用于重头设计的 Database Schema,然后用 syncdb 来同步数据库。
目前 Django 对 ForeignKey 和 One to One, One to Many, Many to Many 支持得都不错,最大的缺陷还是缺乏 Join 的支持导致多表联查的性能不好,这也是我在做开发的过程中碰到的最大问题。
其实用 Django 重头做一个数据库开发非常简单,用下面几步就可以了。
FIRST: Create new project and a new app with django-admin.py $ django-admin.py startproject [project_name] $ cd [project_name] $ django-admin.py startapp [app_name] SECOND: Edit the settings.py file to adjust db settings and installed apps. THIRD: Edit the [app_name]/models.py to modeling the database schema FOURTH: Edit the [prject_name]/urls.py to adjust the path of URL. FIFTH: Edit the [app_name]/views.py to realize your function. SIXTH: To run the manage.py to start the test server in the project. $ ./manage.py runserver THE END: Use your browser to navigate to your http://localhost:8000 and enjoy in it. :-)
这里提供了一个范例,也是昨天在 Launch and Learn 上演示过的:www.box.net/shared/6036abumgv 中的 lnl.tar.bz2 文件,里面提供的 Steps 其实就是上面那段,只是代码中也提供了注释以方便阅读。
scribes 编辑器,不错,不错
自定义了很多 HTML 标签,总算用起来比较顺手了。
稍后把 javascript、python 和 css 的 templates 都完善一下,就发上来。
最好用这个地址看:
Django 和 TurboGears ORM 性能测试完成
连续插入、查询、更改、删除 1000 个记录的测试,其实 ORM 比起在 MySQL 里直接执行真的慢多了(我的代码也得进一步优化)。。。
Django:TurboGears:
下载在:http://www.box.net/shared/877kl03ht7
可以看出 Django 在 Insert 和 Select 动作上速度比较快,而在 Update 和 Drop 上稍慢一些。
这是因为 TurboGears SQLObject 提供了一个 get 方法可以直接获取数据库中对应 id 号的字段,而在做 DROP 操作时我使用了 clearTable 来直接清空表,而 Django 是一条条查询,一条条 delete。
总体上我还是对 Django 的性能比较满意的,这帮人在性能上的优化很 BT ...
PS: 下午给 SQLAlchemy 也做了个简单测试,还没搞明白怎么回事,执行 1000 次插入数据,结果实际只插入了一条,查询语句也有问题,不过性能已经能用”惨不忍睹“来形容了。
如下:
Insert Speed: 0.176656007767Select Speed: 0.0367720127106
Update Speed: 0
Drop Speed: 0
在 Mac OS X 上为 Django 安装 MySQL-python 1.2.2
先去 Sun 网站上下载最新版本的 MySQL, 再去 djangoproject.org 上下载最新版本的 Django 1.0 release, 并且正常安装.
然后用 easyinstall mysql-python, 发现无法正常安装.
查看 easyinstall 的下载路径, 用下面的命令下载并且解压缩
$ cd /tmp $ curl -o MySQL-python-1.2.2.tar.gz http://internap.dl.sourceforge.net/sourceforge/mysql-python/MySQL-python-1.2.2.tar.gz $ tar xvf MySQL-python-1.2.2.tar.gz $ cd MySQL-python-1.2.2
然后修改 site.cfg, 修改下面内容:
由
#mysql_config = /usr/local/bin/mysql_config
改成
mysql_config = /usr/local/mysql/bin/mysql_config
否则会出现找不到 MySQL config 的问题:
... File "/tmp/easy_install-nHSsgl/MySQL-python-1.2.2/setup_posix.py", line 24, in mysql_config EnvironmentError: mysql_config not found
然后修改 _mysql.c, 把第 37 到 39 行注释掉, 如下:
//#ifndef uint //#define uint unsigned int //#endif
否则会出现:
In file included from /usr/local/mysql/include/mysql.h:47, from _mysql.c:40: /usr/include/sys/types.h:92: error: duplicate 'unsigned' /usr/include/sys/types.h:92: error: two or more data types in declaration specifiers error: command 'gcc' failed with exit status 1
然后再用 python ./setup.py build 编译
$ python ./setup.py build running build running build_py copying MySQLdb/release.py -> build/lib.macosx-10.5-i386-2.5/MySQLdb running build_ext building '_mysql' extension gcc -fno-strict-aliasing -Wno-long-double -no-cpp-precomp -mno-fused-madd -fno-common -dynamic -DNDEBUG -g -Os -Wall -Wstrict-prototypes -DMACOSX -I/usr/include/ffi -DENABLE_DTRACE -pipe -Dversion_info=(1,2,2,'final',0) -D__version__=1.2.2 -I/usr/local/mysql/include -I/System/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c _mysql.c -o build/temp.macosx-10.5-i386-2.5/_mysql.o -g -Os -arch i386 -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT gcc -Wl,-F. -bundle -undefined dynamic_lookup -arch i386 -arch ppc build/temp.macosx-10.5-i386-2.5/_mysql.o -L/usr/local/mysql/lib -lmysqlclient_r -lz -lm -lmygcc -o build/lib.macosx-10.5-i386-2.5/_mysql.so ld: warning in build/temp.macosx-10.5-i386-2.5/_mysql.o, file is not of required architecture ld: warning in /usr/local/mysql/lib/libmysqlclient_r.dylib, file is not of required architecture ld: warning in /usr/local/mysql/lib/libmygcc.a, file is not of required architecture
然后再用 python ./setup.py install 安装
$ sudo python ./setup.py install Password: running install running bdist_egg running egg_info writing MySQL_python.egg-info/PKG-INFO writing top-level names to MySQL_python.egg-info/top_level.txt writing dependency_links to MySQL_python.egg-info/dependency_links.txt reading manifest file 'MySQL_python.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'MySQL_python.egg-info/SOURCES.txt' installing library code to build/bdist.macosx-10.5-i386/egg running install_lib running build_py copying MySQLdb/release.py -> build/lib.macosx-10.5-i386-2.5/MySQLdb running build_ext creating build/bdist.macosx-10.5-i386 creating build/bdist.macosx-10.5-i386/egg copying build/lib.macosx-10.5-i386-2.5/_mysql.so -> build/bdist.macosx-10.5-i386/egg copying build/lib.macosx-10.5-i386-2.5/_mysql_exceptions.py -> build/bdist.macosx-10.5-i386/egg creating build/bdist.macosx-10.5-i386/egg/MySQLdb ...
然后用下面的命令进行测试:
$ cd ~ $ python Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import MySQLdb >>> MySQLdb.apilevel '2.0' >>> import django >>> print django.VERSION (1, 0, 'final')
如果能正常输出就没有问题了 :-)