当前位置:首页 > 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)!

相关教程推荐

其他课程推荐