Categories
Links
|
|
django小提示-maxlength,max_length |
在django 0.96,CharField的的最大长度使用maxlength 在svn的代码中,这个已经修改为max_length(这样,更符合python一般的命名规范,当然,事实上python并没有像ruby一样对命名规范有严格的要求,比方说unittest,wxpython就使用两个不同的命名规范),但实际上,原先的代码并不会出错,django是如何达成的呢
这里,django 使用了metaclass的功能
1. 首先,查看Field对象的定义,你会发现 class Field(object): __metaclass__ = LegacyMaxlength
LegacyMaxLength定义在django.utils.maxlength 模块中,这个metaclass非常简单 class LegacyMaxlength(type): def __init__(cls, name, bases, attrs):
super(LegacyMaxlength, cls).__init__(name, bases, attrs) #对构造函数进行修饰 cls.__init__ = remove_maxlength(cls.__init__) #增加maxlength属性 cls.maxlength = property(get_maxlength, set_maxlength)
remove_maxlength巧妙的运用了decorate ,对class 构造进行进行处理,流程很简单,就是从参数中取max_length,maxlength,如果有maxlength,则给你个已过期的警告,如果你同时设置了max_length和maxlength,则给你来个错误(因为 django这样无法判断你用 那个),然后将maxlenth设置给max_length,并创建maxlength属性
这样Field class的代码本身就非常干净,并没有为保持兼容性而同时存在maxlength和max_length两个属性. (虽然实际生成的代码还是有两个的,一个是max_length field还有一个是通过metaclass生成的maxlength property)
这里django 巧妙的利用metaclass实现deprecated 功能的.
在django的代码中,对于类似dsl的功能,django主要利用metaclass和descriptor来达成的,比方说model ,django构造了一个ModelBase metaclass,然后让Model使用这个元类,像对于关系处理, ForeignKey最终是将使用ReverseSingleRelatedObjectDescriptor 这样的 descriptor对象,也就是说,当你遇到 class Customer(models.Model): shipping_address=models.ForeignKey(Address)
最后,这个类被解释执行后的shipping_address实际上是一个叫shipping_address的ReverseSingleRelatedObjectDescriptor 的实例.
descriptor和metaclass的基本知识,我推荐参阅这这几个链接 How-To Guide for Descriptors http://users.rcn.com/python/download/Descriptor.htm#static-methods-and-class-methods 我强烈推荐这个文档, 看后你会知道descriptor 包括property,staticmethod,classmethod到底是如何运作的,也会理解bound(bind)在动态语言中的作用. Python 中的元类编程 -将面向对象编程推向新的高度 http://www.ibm.com/developerworks/cn/linux/l-pymeta/index.html Python 中的元类编程,第 2 部分- 理解继承的奥秘和实例创建 http://www.ibm.com/developerworks/cn/linux/l-pymeta2/index.html
|
| [2007-11-30 15:17:07 | Author:jiangjianxiao ] [] 4 comments |
|
|
django小提示-json |
django提供了基于json,yaml,xml的串行化支持. 这里我们主要来讲json django对json 的支持有两个层次 第一个层次在django.utils.simplejson包中 ,JSONEncoder 提供了常见python数据类型像tuple,list,dict,string,float,decimal等的支持,但这里,并不包含对自定义python对象的json支持 第二个层次在django.core.serializers 包中,这个包提供了对json,yaml(如果你安装了pyyaml的话,xml的串行化支持. 注意,在这里,只能串行化querySet,而且,你只能在django项目内部使用(当然你可以通过手动将项目路径加入到sys.path并设置 os.environ["DJANGO_SETTINGS_MODULE"] = myproject.settings' 来在非django项目中使用)
第一个层次可以在其他非django 项目中使用,你需要继承JSONEncoder,并覆盖default方法,比方说你有一个Employee对象
class Employee: def __init__(self,name): self.name=name
from django.utils.simplejson.encoder import JSONEncoder class ObjectJSONEncoder(JSONEncoder): def default(self,o): if hasattr(o,"__dict__") return o.__dict__ return super(ObjectJSONEncoder,self).default(o)
# test
data=[1,{'a':'a'},Employee('jjx')] import django.utils.simplejson
print django.utils.simplejson.dumps(data,cls=ObjectJSONEncoder)
[1, {"a": "a"}, {"name": "jjx"}]
当使用第二个层次时,你可以通过传递fields 参数选择输出的字段,也可以传入一个io对象
from django.core.serializers import seralize from cStringIO import StringIO stream=StringIO()
seralize('json',User.objects.all(),stream=stream,fields=['username']) print stream.getvalue()
当将json输出到浏览器时,你可以传递mimetype参数为text/json或text/javascript return HttpResponse(json_str,mimetype="text/json")
update django snippets 上有 个JsonResponse类, 可以参考 http://www.djangosnippets.org/snippets/154/
from django.core.serializers import serialize from django.db.models.query import QuerySet from django.http import HttpResponse from django.utils import simplejson
class JsonResponse(HttpResponse): def __init__(self, object): if isinstance(object, QuerySet): content = serialize('json', object) else: content = simplejson.dumps(object) super(JsonResponse, self).__init__(content, mimetype='application/json') |
| [2007-11-28 16:37:21 | Author:jiangjianxiao ] [] 4 comments |
|
|
django小提示-打印sql语句 |
当settings.Debug=True时,django 使用的是django.db.backets.util.CursorDebugWrapper ,这样,当你执行execute,executemany时,django会把你执行的语句加入到BaseDatabaseWrapper派生对象的queries列表,每次加入的是一个dict,包括sql和time 这样,你可以在任何时候打印connection对象的queries属性或是直接在CursorDebugWrapper的execute和executemany中加入print语句 如 def execute(....): ... print smart_unicode(sql) % convert_args(params),"%.3f" % (stop - start)
在django中connection对象实际上就是BaseDatabaseWrapper的派生类 看这行 connection = backend.DatabaseWrapper(**settings.DATABASE_OPTIONS)
再看backend模块是怎么来的 _import_path = 'django.db.backends.' backend = __import__('%s%s.base' % (_import_path, settings.DATABASE_ENGINE), {}, {}, [''])
显然,如果你的DATABASE_ENGINE为mysql的话,这个导入语句就是 __import("django.db.backends.mysql.base",{},{},[''])
通常,mysqldb的cursor执行结果为一个tuple ,虽然这样效率较高,但有时 也不方便,你可以让 在创建真实的mysqldb connection对象时传入cursorclass参数
修改django.db.backends.mysql.base.DatabaseWrapper def _cursor(...): #keargs['cursorclass']=Database.DictCursor # 加上这行 self.connection = Database.connect(**kwargs)
或者在settings.py中增加 import MySQLdb CURSOR_CLASS=MySQLdb.Cusor # 或者CURSOR_CLASS=MySQLdb.DictCursor
然后 def _cursor(...): keargs['cursorclass']=settings.CURSOR_CLASS # 加上这行 self.connection = Database.connect(**kwargs)
你也可以修改 cursor = self.connection.cursor() 为 cursor = self.connection.cursor(settings.CURSOR_CLASS) 效果是一样的 |
| [2007-11-28 11:05:03 | Author:jiangjianxiao ] [] 2 comments |
|
|
asp.net mvc笔记- 替换自己的view engine,依赖注入 |
使用自己的view引擎
asp.net mvc 的view引擎提供对asp.net page,usercontrol 的的支持. 你还可以创建自己的view引擎,过程非常简单1. 实现IView接口,比方说 public class NVelocityView : IView { public string ViewName { get; set; } public string MasterName { get; set; } public object ViewData { get; set; } public void RenderView(ViewContext viewContext) { //用nvelocity解析模板,这个任务留给大家完成 string context = string.Empty; context = "解析后的内容";
viewContext.HttpContext.Response.Write(context);
}
}
2. 实现IViewFactory接口 public class NVelocityViewFactory : IViewFactory {
public IView CreateView(ControllerContext controllerContext, string viewName, string masterName, object viewData) {
return new NVelocityView { ViewName = viewName ,MasterName=masterName,ViewData=viewData}; }
} 3. 继承Controller类,在类构造中设置ViewFactory参数 public class HomeController : Controller { public HomeController() { ViewFactory = new NVelocityViewFactory(); } [ControllerAction] public void Index() { } }
依赖注入
4. 实现 IControllerFactory 在这里进行依赖注入,比方说调用 public class SpringControlFactory : IControllerFactory {
public IController CreateController(RequestContext context, System.Type controllerType) { string requiredString = (string)context.RouteData.Values["controller"]; return (IController)ContextRegistry.GetContext()[requiredString];
}
} 5. 设置controlerfactory 代码放到global.asax 的Application_Start中 ControllerBuilder.Current.SetDefaultControllerFactory( typeof(SpringControlFactory)); 更新 ControllerBuilder提供了SetControllerFactory和SetDefaultControllerFactory两个方法, 通常,SetControllerFactory是针对特定的controller类型的, 在这个场景,你想对所有的controller子类生效,就用 SetDefaultControllerFactory
通过依赖注入,我们可以在外部实现修改ViewFactory的功能 <object id="myViewFactory" type="xxx.NVelocityViewFactory,xxx"/> <object id='Home' type="xxx.HomeController,xxx" singleton="false"> <property name="ViewFactory" ref="myViewFactory"/> </object>
IControllerFactory 非常重要, 这里,你可以使用dlr ,整合ironpython和ironruby,因为你已经得到controller名,接下来你可以从文件系统中读取对应的ironpython或ironruby 文件,编译和执行它,返回给asp.net mvc 这个链接 描述了如何host ironruby 2.0 r6 http://blogs.msdn.com/rdawson/archive/2007/11/29/hosting-ironpython-2-0-alpha-6-via-the-dlr.aspx 而codeplex 上有个nwsgi 项目, 你可以参考如何使用ironpython来达成在asp.net实现一个wsgi实现的
大家可以看到,继承自己的view引擎和ioc功能和整合动态语言是非常简单的, asp.net mvc 只是提供了一个简单的层次.对于类似castle 项目,两者更多的是互补而不是竞争.比方说castle的route功能不强 ,orm 不足,更多的是缺少社区的关注. 利用asp.net mvc ,castle 可以更多的将眼光关注到具体的领域问题上.
|
| [2007-11-26 18:03:58 | Author:jiangjianxiao ] [] 3 comments |
|
|
nwsgi |
nwsgi是一个asp.net 上的wsgi实现(使用asp.net ihttphandler), 这样,理论上,你可以在asp.net 使用那些wsgi兼容的python web framework . 当然,最终能不能用,还是要看ironpython .一般来说,没有和c扩展交互的python应用,大部分可以顺利运行. 作者的例子中也用了paste/cherrypy. 不过至于django/pylons 之类的,就别想了.
这项目还没有release,你可以从sourcecode中下载.如果打算用ironpython 做自己的web框架,使用nwsgi+paste或许是个不错的起点
下载地址 http://www.codeplex.com/NWSGI |
| [2007-11-14 15:21:19 | Author:jiangjianxiao ] [] 1 comments |
|
|