当前位置:首页 > Python教程 > python技巧

初识python django, 让我们一起进入python的世界吧


这几天花时间学习了一下 python django ,正如某人所说,掌握另外一门语言是有必要的,同样我也作出了自己的选择。从这几天的学习中,我确实也发现其他语言及其框架等确实有一种与众不同的感觉。下面我把自己这几天看到的东西稍微作了一下总结,本文并不是 django 的教程,而是在麦子学院参加学习之后对 django 的一些自己的理解,可能有些不成熟的地方,希望大家不要吝惜手中的砖头。  


django orm  
如果有人问我喜欢 django 的什么,我会耗不犹豫的告诉你是 django orm ,这个想法的产生完全来自于我长时间来积累的对 hibernate 不满 ,虽然从理智的角度来看, hibernate 做的是非常的正确的,因为它并不是只针对互联网而产生的,它的主要市场应该还是在企业应用上,不过把它用在互联网并非不可以,只不过大家更多的时候会选择 ibatis 之类,因为不知道 hibernate 的人总是会说 hibernate 没有 ibatis 快(其实我最烦这个,片面的比较是没有意义的)。正是 hibernate 的目标是打造成 java 界一个全方位,全能的 orm 框架,所以的它学习曲线和使用的复杂度日益的提升,要完全掌握好 hibernate 不是一件容易的事情(不要告诉我你会点 crud ,知道点 lazy load 你就掌握好 hibernate 了),再回头来看 django orm ,如果说要把 hibernate 说清楚需要 800 页的书,那么要把 django orm 说清楚, 200 页就够了 ( 事实上它的官方文档只有十几页的样子 ) 。下面我举一个我正在做的例子,这里有一个自关联的对象(事实上 django orm 是基于 model ,这点和 ror 不太一样,有人跟我讲过 ror 是数据库驱动),这个对象有一个父对象,通常我们的菜单会定义成这样的对象,这样的菜单可以无限级向下扩展:  

Python 代码    

1.  class  Category(models.Model):  

2.      id = models.AutoField( ‘id‘ , primary_key= True )  

3.      name = models.CharField(maxlength= 50 )  

4.      code = models.CharField(maxlength= 50 )  

5.      parentCategory = models.ForeignKey( ‘self‘ ‘id‘ , null= True )  

6.      enable = models.BooleanField()  

7.        

8.       def  __str__( self ):  

9.           return   self .name  

10.       

11.      class  Admin:  

12.         list_display = ( ‘id‘ ‘name‘ ‘code‘ ‘parentCategory‘ )  


Category
中又定义的 Admin 是为 django Admin 模块服务的。  
瞧,我们定义的域模型只需要这些代码就够了, models.Model 是父对象,所有的 model 对象都需要继承这个对象,这个对象提供了很多常用的数据库方法,不过不是基于 sql 的,还是基于对象的,如同 Criteria 一样。下面列出常用的一些查询 Category 的方法。  
1

引用

Category.objects.get(id = request.POST[‘category‘])


查询 category by id (从页面上传过来的)  
2

Python 代码    

1.  categoryList = Category.objects.filter(code__contains = “a”,enable =  True ).order_by(“-id”)[ 0 : 5 ]  

,按 id 倒序,查询 enable 属性为 True , code 中包含 a category, 且取前 5 , 是不是有很强烈的 criteria 的味道  
3

Python 代码    

1.  category.save()  

保存或者更新某个 category 对象(类似 saveOrUpdate 操作),充血模型, dao 消失了。  

4

Python 代码    

1.  category.delete()  

删除某个 category 对象 , 当然 delete 方法也是支持批量删除,比如

Python 代码    

1.  categorys.delete()  



5
复杂的查询可以使用 extra 方法,例如:  

Java 代码    

1.  Category.objects.extra(where=[ ‘id IN (3, 4, 5, 20)‘ ])  

,还可以使用字符替换法 , 如:  

Java 代码    

1.  Category.objects.extra(where=[ ‘code=%s‘ ], params=[ ‘a‘ ])  



当然 django orm 提供了很多很常用的功能,这里不一一举例了,注意,这里我说的是提供了很多很常用的功能,至于 hibenate 中比较复杂的映射策略,在 django 中我并没有看到。但是我反而高兴我没有在 django 中找到这个功能,因为 django 本身的定位是快速的互连网开发,它不需要太多的关注这个领域很少出现的东西,这样带来的优点是学习曲线的降低和开发效率的提高。  

django 的模板  
Django
的模板可以说是非常的简洁,简洁到我不知道说什么好,简洁到看一下文档就能上手使用,在 java 中, freemarker velocity 我都用过,最复杂功能最强大的还是 freemarker ,支持 jsp tag 的嵌入让我们可以重用很多已经存在的组件,这一点我在之前的文章中也有过比较详细的描述 ( 强强联手,看 freemarker displaytag 的结合 ) ,由于了解,才有发言权, django 的模板可以说是为互连网应用而诞生的,简洁及快速开发的特点让人情不自禁的喜欢。大多数模板语言的基本语法都是类似的,比如在 freemarker 中显示值是 ${} ,而在 django {{}} freemarker if 判断为 <#if></#if> ,而 django 中是  

Java 代码    

1.  {%  if  msg %}  

2.      Xx  

3.  {%  else  %}  

4.  Xx  

5.  {% endif%}  



再看看在 django 中渲染模板的方法,有两种 :  
第一种  

Python 代码    

1.  def  preparePublish(request):  

2.      t = loader.get_template(publishInfo)  

3.  return  HttpResponse(t.render(Context({ ‘categoryList‘  :  None })))  


第二种  

Python 代码    

1.  c = Context({ "categoryList" :categoryList})  

2.  return  render_to_response(indexPage, c)  


render_to_response
相当于封装了 loader.get_template 方法而已 , 所有的一切看上去都是那么的简单 , 模板无处不在,今天你模板了吗?  

插一句题外话,关于 jsp 的题外话,不管是 ruby ,还是 c++ ,还是 python ,在它们的 web 框架中都使用了模板, java 中也有很多模板,我们最熟悉的是 freemarker velocity 。这从一个侧面反映出我们 web 开发中的一个模式,那就是我们的 view 基本上是基于模板产生的,而 jsp 这个东西应该来说是时代的产物,在那个混乱的落后的时代产生的,不过很奇怪的是现在还有这么多人抱着它不放。  

django form  
Django
有两种 form ,一种是自己定义 form class ,还有一种是通过我们定义的 model 自动 form class  
由于 ahuaxuan 只做 了一个信息发布的小例子,所以并不能全面的了解或者理解 django form 的所有细节,不过从我涉及到的部分来讲,我对 django 的从模型创建表单的做法确实感到有比较大的局限性,因为很多时候, model 中的数据 并不是从页面上来的,在这种情况下, form 对象被构造出来之后, ahuaxuan 还没有找到修改 form 中值的方法。  
而自定义 form 类也比较麻烦,就是要写自己的 model ,这个和我们之前的做法比较不一样,这里的 form 代表我们 java 中的 value object model domain object ,在我们的 ssh 框架中我们通常把 value object 继承我们的 domain object 。虽然一堆又一堆的人提出了反对意见,说要把这两个对象分开,因为他们处在不同的层次中,但是从实践经验中,我们可以看到,这样做没有什么不好。而在 django 中自定义 form model 分开的行为可能比较符合一些人的心理。  
不过自定义 forms 也有比较让人称道的地方,在 form 中我们可以自定义验证规则,同时我们可以根据 form 对象直接生成页面中的内容,不过这一点其实也有比较麻烦的地方,就是如果要改变样式的时候就比较麻烦。不过总的来说 django form 还是比较有特点的,而且一定程度上给我们带来了方便。  


django url 转发  
Django
url 转发是基于正则表达式的,有的人叫好,有的人叫差,我就是叫差的那一拨人之一。 url 转发应该是一个非常清楚,非常明亮的事情,可是用上这个正则表达式匹配的东西之后,我郁闷了,所以我只能回到遥远的过去去绕过这个东东,我不用总可以了吧。  

从目前目前掌握的知识来看, django views 里的东西其实是 controller ,为什么叫 views ?不得而知,不过一直这么沿用下来了,即使是在自然界,很多表面上去不太一样得东西,其实内部的原理是一样的,我就觉得 django views 就是 struts1.x 中的 action ,为什么这样说呢,让我们来看看两段比较的代码,第一段是 django 的,第二段是 struts1.x 的:  

Python 代码    

1.  def  index(request):  

2.        

3.      categoryList = Category.objects.filter(enable =  True )  

4.       for  cate  in  categoryList:  

5.          informationList = Information.objects.filter(category = cate)[ 0 : 5 ]  

6.          cate.informationList = informationList  

7.            

8.      c = Context({ "categoryList" :categoryList})  

9.  return  render_to_response(indexPage, c)  





――――――――――
分隔线 ―――――――――――――――  

Python 代码    

1.  public ActionForward getSechandIndex(ActionMapping mapping, ActionForm form,  

2.                                           HttpServletRequest request,  

3.                                           HttpServletResponse response)  

4.              throws Exception {  

5.          setBargainIndex(request);  

6.           return  mapping.findForward( "bargainHome" );  

7.      }  


从形式上来看,两者出奇的相似,比如说传入的参数等。我们知道 python 是面向对象的语言,但是事实上它也支持函数编程,如果 def 定义在 class 内部,那么就是对象的方法,否则,就可以认为是函数编程了,看看,我们的 views 里的东西都是函数, views 其实是一个模块,这个模块我们可以认为是 struts1.x 中的 action ,而 views 中的函数可以认为是 action 中的方法。它们是远房亲戚。  

那么说到这里,曲线救国的线也找到了,就是 struts.1x DispatchAction ,我们只要在 url 后面追加一个 methodName 就可以指定我们要调用 views 中的哪个函数了。代码如下:  

Python 代码    

1.  def  execute(request):  

2.      methodName = request.GET[ ‘methodName‘ ]  

3.       return  getattr(mark.views, methodName)(request)  



这个 execute 方法成为了所有的方法的入口(我们在 urls.py 中只需要这样定义:

Python 代码    

1.  (r ‘^$‘ ‘inforplatform.bargin.views.execute‘ )   



接着在 execute 方法中判断 methodName 的值,然后根据这个值找到对应的函数,再调用它, getattr 类似于 java 中的反射,可以让我们动态调用任何我们想调用的函数(只要我们知道函数名的话)  

这样我们在 urls.py 中只需要定义很少的值 ( 有几个模块就定义几行就够了 ) 就可以完成我们的项目了,以后维护起来也没有这么麻烦和复杂。  
一个小小的缺憾是没有自带 restful ,不过听说有一个插件可以支持。  

admin  
Django
admin 功能号称是 django 的杀手级特性 (killer feature) ,这一说可以说是恰如其分,毫不夸张的,从我做的这个例子来看,当我做网站的时候,基本上只需要关注前台页面的展示这部分,后台的功能基本上都自动有了,比如我做的例子是一个二手信息发布平台, category 是二手信息的类型,还有一个 information 类,和 category 是多对一的关系,那么在后台, category information crud 就自动生产了,由于 category 本身是一个自关联,所以在 admin add category 的时候, admin 会根据我 model 的定义,自动要求选择一个 parentCategory ,而在 add information 的页面上, admin 会要求我选择一个 category 来完成对一个 information 的创建,而以前在 java 中,这些工作都需要自己完成,当然也有很多工具可以自动生产 crud ,不过这些开源的工具基本上都是针对单个 model 的,而且生成的代码需要很大修改才能真正的把功能跑起来,最重要的一点是不能自动生成关联关系的管理。当然我也见过有公司做了基于数据库驱动的代码生产器,能生成完整可用的代码和页面,也包括关联关系的处理,不过由于语言特性的区别,在开发的时候我们还是要不停的重启 server 才能显示出效果来,虽然在技术上,为 ssh 实现这个功能并不难,但是会消耗不少时间在上面,消耗了很多时间的话,很少就有公司将其贡献出来了。所以个人认为 django 在这个功能上做得还是非常不错的,尤其这个功能可以节省开发者很多的时间。甚至有些时候,项目可以双线执行,用户通过 admin 输入数据,程序员开发前台,这样,前台功能做完之后,数据也有了,基本可以测试上线了。在需要快速开发的小项目上,这个特性显得尤其重要,因为 django 产生得时候就是基于这个场景。  

当然有时候后台也没有这么简单,不过还好, admin 提供了扩展的功能,我们可以自己写扩展的代码,然后集成到 admin 中去,不过事实上除了能改变 admin 的模板,我们不能改变任何 admin 的代码,不过我时常在想,如果 admin 支持代码自动生成的功能,那岂不是很美妙,我们可以随意的修改后台的功能了,否则我们就需要自己写代码,不如在生成的代码上扩展方便。  

要使用 admin ,必须打开 django 的权限模块,这里简单介绍一下权限模块, django 自带了一个权限模块,这个权限模块中的 model 对于熟悉权限这块的人来说再熟悉不过了, user group permission user group 多对多, group permission 多对多,在 acegi 中,我们通常这样定义, user role resource ,这个和 django 中的权限是一样的,不过在 django 中默认的 permission 的粒度是非常的粗了,是基于 model 的,如果我们要更细的权限模块,那么就需要自己扩展了。  

总的来说 admin 给我的惊喜大于失望,虽然有点小小的不满意,但是总体来说还是非常赞的  

部署  
在这部分开始之前我也想聊聊之前我们一直在讲,而且将来还一直会讲下去的一个话题 ―― 状态。  
之前我们一直在讨论,把用户的状态保存在一个集中的地方,尤其是大规模集群部署的情况下,同样,对于 django 来说亦是如此,可以说这条金科玉律不只是针对某种针对某个语言,某个框架,它应该是更高层次的一种理念。那么我们可以把状态放到什么地方呢,目前一些流行的选择是 DB( 内存表,或实体表 ),memcached ,或者 cookie ,但这几种选择并不是可以随便互换的,比如业务数据较多的情况下,放在 cookie 中不是很合适,因为有可能超出 cookie 大小的限制,那么放在 memcached 中,很遗憾, memcached( 使用 slab 的情况下 ) 中也有它自己的限制,如果状态数据大小跨度较大,那么丢数据的情况有可能发生, ahuaxuan 很久之前在测试环境下就碰到过这种情况,由于线上 memcached 开得较大,所以没有出现这种情况,关于这种事件发生得内部原因在 ahuaxuan 的另外一篇文章中已经有了非常详细的描述。那么放在 DB 上呢,显然, DB 的压力也是我们需要考虑的问题之一。当然除了这些主流的选择之外,我们其他选择还有很多,比如 memcachedb ,或者 timesten ,或者其他等等,但是对于状态这种东西,尤其状态数据比较重要的情况下,我们一定要深入研究并理解状态数据的存储技术,否则可能会遇到我们异想不到的情况,比如很久之前我想破头也不会想到 memcached LRU 是针对某个 slab ( 而且我还要插一句, LRU 的时候其实并不是遍历 slab 中的 chunk 链表,而且只遍历最开始的 50 个数据而已,这样做纯粹是为了速度 )  


目前对 django 来说基本上有两种部署策略,  
第一种是利用 mod_python django 运行在 apache 进程中,还有一种是 webserver+fastcgi ,这两种方式各有优缺点,在 mod_python 模式中,我们的 webserver 必须使用 apache apache webserver 这一领域已经独占鳌头很多年了,市场占有率也是远远的超过其他的 webserver ,不过近几年来,又崛起了几个其他的 webserver ,其中比较出名的是 ligttpd nginx ,它们都以高性能和低内存消耗对 apache 发出了挑战,而 mod_python apache 的插件,使用这种方式就把我们的 webserver 限定在 apache 上了,不过还好 apache+mod_python 也是非常的稳定的方案了。  

第二种就是 webserver fastcgi ,这里的 webserver 就可以随意选择了,大多数的 webserver 对提供了对 fastcgi 的支持,比如我们耳熟能详的 lighttpd nginx ,而且据称在很多情况下, FastCGI 能够提供比 mod_python 更为优越的安全性和效能。针对小型站点,相对于 Apache 来说 FastCGI 更为轻量级。据称 qq 的个人空间就是 c++ fastcgi 实现的,哦,这样做的优势在哪里呢, c++ 的处理速度将会非常的快,也就是说每个 fastcgi 处理一个请求将会非常快速,比如使用 python 需要 50 毫秒, c++ 处理这个请求有可能只需要 20 毫秒(这个例子未必准确,只是为了说明 fastcgi 的特性),虽然在开发上 c++ 比较麻烦一点,不过在性能上, c++ 肯定是 no1 了,从这个例子上我们可以看到,使用 fastcgi 速度取决于处理一次请求的速度(废话,哪个不是这样)。  

我们来看一下使用 fastcgi 的一般模式: 1 WEB 服务器收到客户端的页面请求 2 WEB 服务器将这个页面请求委派给一个 FastCGI 外部进程( WEB 服务器于 FastCGI 之间是通过 socket 来连接通讯的) 3 FastCGI 外部进程得到 WEB 服务器委派过来的页面请求信息后进行处理,并且将处理结果(动态页面内容)返回给 WEB 服务器 4 Web 服务器将 FastCGI 返回回来的结果再转送给客户端浏览器。  
对我们来说第 3 步是我们最需要关注的,因为第 3 步的速度严重影响着整个性能。由于 fastcgi 是基于进程的,所以,我们要根据我们的应用来开启数量合适的 fastcgi 进程,多开了是对资源的浪费,少开了就影响性能,这个类似我们在 tomcat 中开启处理请求的 thread 一样,只不过 tomcat 中的 request handler thread 在配置起来显然更加方便,因为我们只要关注线程池中最大的可以容纳的线程数,最大空闲线程数等就行了。  

当然 fastcgi ahuaxuan 这类刚刚跨出 java 世界的人来说有些不爽的地方,因为基于进程的东东共享数据比较麻烦,比如写一个 ip 查询的组件,功能是这样的,把 ip 地址库加载到内存,然后根据客户端的 ip 使用折半搜索改 ip 所在的城市,用 java 做非常的方便,先把几兆的数据加载到内存中,然后每个线程都来请求就可以了。而对于 fastcgi 来就比较麻烦了,需要把这些数据加载每个 fastcgi 进程中,无辜浪费掉一堆内存。不过有得必有失,因为每个 fastcgi 只能同时处理一个请求,所以使用 fastcgi 就基本不需要考虑多线程的问题了。  

通过几天时间的学习,确实使我更加了解了 python 以及 django ,但是我也知道要掌握一门语言和技术需要的肯定是不止几天而已,几天可以说只是入门 , 说的不对的地方恳请大家批评指正


原文:http://my.oschina.net/u/2415107/blog/483023


【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!

相关教程推荐

其他课程推荐