认识Django的Class-Based-View

学习Django非常简单,几乎不用花什么精力就可以入门了。配置一个url,分给一个函数处理它,返回response,几乎都没有什么很难理解的地方。

写多了,有些问题才逐渐认识到。比如有一个view比较复杂,调用了很多其他的函数。想要把这些函数封装起来,怎么办?当然,可以用注释#------view------这样将函数隔离开,这种方法太low了,简直是在骗自己,连封装都算不上。

Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:

  1. 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
  2. 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性

使用class-based views

如果我们要写一个处理GET方法的view,用函数写的话是下面这样。

如果用class-based view写的话,就是下面这样。

Django的url是将一个请求分配给可调用的函数的,而不是一个class。针对这个问题,class-based view提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用相应的方法来处理request(如get(),post()等)。到这里,这些方法和function-based view差不多了,要接收request,得到一个response返回。如果方法没有定义,会抛出HttpResponseNotAllowed异常。

在url中,就这么写:

类的属性可以通过两种方法设置,第一种是常见的Python的方法,可以被子类覆盖。

第二种方法,你也可以在url中指定类的属性:

使用Mixin

Django中使用Mixin来重用代码,一个View Class可以继承多个Mixin,但是只能继承一个View(包括View的子类),推荐把View写在最右边,多个Mixin写在左边。Mixin也是比较复杂的技术,本文不详细说了,以后写一篇针对Mixin的文章吧。

使用装饰器

在CBV中,可以使用method_decorator来装饰方法。

也可以写在类上面,传入方法的名字。

如果有多个装饰器装饰一个方法,可以写成一个list。例如,下面这两种写法是等价的。

 

参考资料

  1. Introduction to class-based views
  2. Django 1.6 最佳实践: 如何正确使用 CBVs (Class-based views)
 

VimScript学习笔记(4):状态条

Vim的状态条支持自定义,键入下面这条命令,会让Vim的状态条只显示文件名。

状态条的格式和C语言的printf以及Python格式化字符串的方式很像,支持左对齐,右对齐,最小宽度,0补位等等。具体格式如下:

此外,使用下面这种方式定义,可以大大增加可读性。

更多相关的细节,以及Vim支持的所有状态,可以在Vim中使用:help statusline命令查看。

至此,基本的Vim命令已经差不多了。相关概念已经准备好了,即使遇到不会的,也可以通过Google+help文档解决。下面开始,就要将VimScript作为一个真正的Script编程语言来学习了。

 

VimScript学习笔记(3):补位映射(Operator-Pending Mappings)

这个Operator-Pending Mappings比较难翻译,字面意思是,一个操作要干什么,取决于后面跟的东西。比如g这个跳转命令,g后面跟个g就是跳到文章开头,如果跟个$就是跳到最后一个字符。本文说的Mappings,指的就是决定操作的后面的东西(movement)。可以这么想,这些命令后面需要跟一个变量,我们声明好这个变量(定义映射),然后用命令+变量的方式就可以调用了。

下面是一些类似命令的例子:

移动映射(Movement Mappings)

这个映射比较简单,和前面学到的映射没有很大区别。下面这个,将p映射为i((在括号之内的意思)。

测试:键入下面的文字。

将光标移到括号之内,输入dp,会发现括号之间的内容被删掉了。

使用u撤销删除,键入cp,发现进入了Insert Mode,可以修改括号之间的内容了。

再来一个,键入下面这个映射:

然后输入下面的测试文字:

在第一行输入命令db,发现函数体被删掉了。

定义一个移动映射的时候,可以参考下面这个步骤:

  1. 将光标移动到需要操作的文字开始的地方
  2. 进入可视模式(Visual Mode)
  3. 想办法将光标移动到你要操作的文字那里
  4. 结束,你要操作的文字已经选中了

其中,第3步就是你需要的操作,将这些操作映射到某个键就可以了。

映射开始的位置

上面这种方法有个不便之处,也许你已经发现了。就是每次我们执行命令的时候,都要将光标移动到要操作字符的开始位置,很不方便。

其实,我们可以定义选中文字的映射,然后通过命令来操作被选中的文字。此方法通过下面的例子学习。

键入下面这个命令:

测试,输入下面的文字:

光标移动到print上,键入cin(,会发现我们可以修改括号里面的内容,而不用将光标移动到括号内了。

<c-u>的作用在这里暂时忽略,不影响我们学习本章内容。

normal!的作用是,将后面的命令在Normal Mode下执行。为什么不直接写映射,要加这个呢。我试了一下,如果直接映射的话,Vim会作为连续的按键执行,执行到i可能就打断了,进入插入模式。

f(vi(比较好理解了,找到下一个括号,v进入Visual Mode,标记括号里面的内容。

至此,这个映射完成了选中文字的任务,剩下的就可以配合Vim命令处理了。

区别两种方式

上面这两种Operator-Pending的方法很好区分:

  • 如果映射最后选中的一部分文字,那么命令就会去操作选中的文字
  • 如果映射最后是跳到一个位置,那么命令就回去操作从光标原先的位置,到光标最后跳到的位置之间的文字

练习

MarkDown文本中,=======上面的文字会被视作标题。下面这个映射,选中了光标所在章节的标题。

测试,输入下面的文字。

在It…这一行,键入cih,会发现标题被替换掉了。

如果不能理解,可以参考这里

 

Django的数据迁移(Data migration)

Django支持ORM模型,我们不必写一条SQL语句,就可以方便使用面向对象管理数据库。数据库的管理可以分为结构迁移和数据迁移。

结构迁移是只是指表的结构改变。我们只需要修改Django的数据模型,然后用python manage.py makemigrations自动生成需要执行的数据迁移代码(一般保存在app/migrations文件夹下),然后用python manage.py migrate执行代码,就可以将变化应用到数据库。

另一种是数据迁移。之前我的做法是,写一个url映射到view,在view中写操作数据库的代码。执行完毕后删掉url。这样做有很多坏处:

  1. 将操作数据库开放了(即使可以写管理员权限)
  2. 污染url和view的代码
  3. 不能将所有有关数据库管理的代码放下migrations下面

好处是,如果常用的话,可以作为管理员“维护数据库”的一种方式。但如果是这种用途的话,还是写成一个中规中矩的view比较好。

其实,Django本身就有数据迁移的功能,上面这种做法太“歪门邪道”了。

数据迁移和结构迁移类似,只不过Django不是直接为你生成迁移结构的代码,而是生成一个框架,然后你在这个框架根绝自己的需要写代码。其实这个样子更灵活。

1.生成数据迁移的空白文件

执行下面的命令,生成一个迁移的脚本,等着你填上需要执行的命令。

生成的空白文件,如下所示。

2.填写数据迁移代码

文件中的Operations是空着的,这个地方是需要执行的数据迁移操作。数据操作可以写成函数,然后在Operations里面用RunPython运行函数。

函数的第一个变量是app,第二个是SchemaEditor,可以用来手动修改数据表的结构。不过不推荐这样做,做自动迁移的时候可能遇到问题。

下面这个迁移是自动根据以前名字的firstname和lastname生成name。导入模型的方式有点特殊,将要做的操作写到Python函数里面,然后在Operations里运行Python函数。除了RunPython之外,也可以RunSQL等等。

3.执行migrate命令,应用数据迁移

和应用结构迁移一样,执行下面的命令就可以了。

4.使用其他app里面的Model

如果RunPython函数里面用到别的app(不是此migrations存在的app)里面的model,应该在Dependencies里面模仿例子加上别的app的名字以及最新的migrations依赖。

否则,使用apps.get_model()的时候,会遇到LookupError: No installed app with label 'myappname'

下例,app1里面的migrations用到了app2的Model。

5.参考资料

  1. Django文档,Migrations
 

配置lisp开发环境

对lisp的支持,Emacs的是比较好,有Slime。后来,Vim也相应的出了Slimv,可能毕竟没有Emacs流行吧。一开始我的选择是Slimv,毕竟比较习惯vim了。但是安装这个插件遇到了很多问题。

对Vim的尝试

官方教程是直接下载插件放到vim目录下安装,我偷懒直接用Vundle从github安装的,结果运行出错。去google一下,发现这个项目下面有一个和我一模一样的错误:SlimvInitBuffer not defined。这是由于Vim对函数前缀b:的错误,之前的版本是直接忽略掉的,但是从vim7.4之后,就有问题了。参考这个issue,删掉所有的:b前缀就可以解决,因为其实:b什么都没有做。删掉是没有错误了,大还是我的REPL还是没有出现。

只好回到官方toturials上面了。发现上面说vim是需要pyhton-enable的,我去vim查看了一下版本,发现我的vim没有支持python,支持的是python3,只好重新编译安装。编译安装的过程可以参考这里。其实也可以不必重新安装,使用update-alternatives,可以直接将vim指定到python2.

花了很多时间之后,按照官方的教程下载,发现并没有启动,百般周折,最后还是选择了Racket。

最终选择Racket

Racket的前身是DrScheme(PLT-scheme?)现在plt-scheme的主页直接指向racket了。

安装方法是(ubuntu):

  1. 从https://download.racket-lang.org/ 下载安装脚本。
  2. chmod +x [下载到的脚本名字]
  3. sudo ./[脚本名字]

话说用111M的一个单文件sh,这么样的安装方式我还是第一次见……安装好之后,可以从ubuntu的GUI打开软件了。用官方的example试一下吧: