给Cmd传递外部参数


Cmd类可以处理外部参数,比如我们的Cmd类中包含一个greet方法,现在我们可以通过外部参数直接运行这个命令。比如:

import cmd

class InteractiveOrCommandLine(cmd.Cmd):
    ””“
    Accepts commands via the normal interactive
    prompt or on the command line.
    “”“

    def do_greet(self,person):
        if person:
            print ‘hi:’,person
        else:
            print ‘hi’

    def help_greet(self):
        print \n.join([‘greet [person]’,
                         ‘Greet the named person’])

    def do_EOF(self,line):
        return True


if __name__==’__main__’:
    import sys
    if len(sys.argv)>1:
        InteractiveOrCommandLine().onecmd(’ ‘.join(sys.argv[1:]))
    else:
        InteractiveOrCommandLine.cmdloop()

执行下面的命令:

$ python cmd_args.py greet Command_Line User
hi: Command_Line User

from http://bit.ly/JWinwx

通过Cmd执行命令行脚本文件


Cmd除了可以用于开发一个命令行交互环境外,还可以直接通过它读取一个包含Cmd命令的脚本文件并执行其中的命令。下面是一个例子:

import cmd

class HelloWorld(cmd.Cmd):
    ””“
    Simple command processor example.
    “”“

    #Disable rawinput module use
    use_rawinput = False

    #Don’t show a prompt after each command read
    prompt =
   
    def do_greet(self,person):
        if person:
            print ‘hi:’,person
        else:
            print ‘hi’

    def do_EOF(self,line):
        return True


if __name__==’__main__’:
    HelloWorld().cmdloop()

假设脚本文件为cmd_file.txt,其中包含的命令为:

greet
greet Alice and Bob

执行命令如下:

$ python cmd_file.py cmd_file.txt

hello,
hello, Alice and Bob

from http://bit.ly/JWimc3

通过Cmd运行系统命令


Cmd类不仅可以定义命令行交互环境,还可以调用系统命令,方法是通过继承cmd.Cmd,重载do_shell方法。比如下面的例子:

import cmd
import subprocess

class ShellEnable(cmd.Cmd):
    last_output=
    def do_shell(self,line):
        “Run a shell command”
        print “Run shell command:”,line
        sub_cmd=subprocess.Popen(line,shell=True,stdout=subprocess.PIPE)
        output=sub_cmd.communicate()[ 0]
        print output
        self.last_output=output

    def do_echo(self,line):
        ””“
        Print the input, replacing ‘$out’ with
        the output of the last shell command.
        “”“

        #Obviously not robust
        print line.replace(‘$out’,self.last_output)

    def do_EOF(self,line):
        return True


if __name__==’__main__’:
    ShellEnable().cmdloop()

然后我们在执行的命令行交互环境中运行?可以查看可执行的预定义命令,通过“shell + 系统命令”的方式运行系统命令:

(Cmd) ?

Documented commands (type help <topic>):
========================================
echo  shell

Undocumented commands:
======================
EOF  help

(Cmd) ?shell
Run a shell command
(Cmd) shell dir

from http://bit.ly/LOQBAU

基于对象的通用视图举例ListView


我们前面讲过Django的简单视图,比如TemplateView和RedirectView。其实Django通用视图真正出彩的地方是它能够显示一个模型对象的列表信息。比如我们有下面几个模型类:

# models.py
from django.db import models
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()
    class Meta:
        ordering = [“-name”]
    def __unicode__(self):
        return self.name
class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(’Author’)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

假设现在我们要显示数据库中保存的所有的Publisher对象,那么可以在urls.py中使用ListView视图类:

from django.conf.urls.defaults import *
from django.views.generic import ListView
from books.models import Publisher
urlpatterns = patterns(’’,
(r’^publishers/$’, ListView.as_view(
model=Publisher,
)),
)

这几乎就是所有的代码,如果你要指定模板文件的路径,可以通过as_view函数的 template_name 参数实现。如果你不指定,Django会推断出一个模板路径,针对上面的例子是:“books/publisher_list.html” 这里的books是Publisher所在的应用程序名,然后Django把Publisher模型类小写,后面的_list表示显示它的列表信息。
因此,你需要在你的对应的模型路径下创建这个模板文件(比如:/path/to/project/books/templates/books/publisher_list.html)

其中的内容可以是这样:

{% extends “base.html” %}
{% block content %}
<h2>Publishers</h2>
<ul>
{% for publisher in object_list %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
{% endblock %}

object_list 这个变量时ListView.as_view()函数生成的代表Publisher集合对象的默认参数名称。看看,是不是简化了很多?


from http://bit.ly/JQPXsz

使用通用视图类简化视图层的编码


Web开发有时候是很乏味的一件事,我们不得不重复一些单调的工作。为此,Django在模型层和模板层提供了很多工具和模式来简化开发。同样,在视图层Django也尝试提供一些简化开发的方法。比如这里要介绍的通用视图。

Django提供的通用视图一般用于完成以下操作:

1. 执行一些“简单”的任务,比如重定向一个请求,装饰一个模板页面等。

2. 显示一个对象的详细信息列表。比如我们创建了一个conference(会议)对象,它包含TalkListView 和一个RegisteredUserListView 视图,它们都是列表对象。

3. 显示包含年月日的日期对象。比如Django网站的Blog空间就使用了日期对象通用视图函数。

4. 在授权许可的情况下,执行一些增删改对象的操作。

这些视图都是以一个Python类来实现的。我们看一个间的例子。比如我们有一个about.html页面,它用于显示站点的介绍信息。对于它的要求非常简单,内容是纯粹的HTML信息,没有动态内容。这是我们可以使用TemplateView通用视图类。不过由于我们要修改具体的about.html的位置,因此我们可以继承这个类:

# some_app/views.py
from django.views.generic import TemplateView
    class AboutView(TemplateView):
        template_name = “about.html”

接下来是在urls.py中配置这个视图的URL路径:

# urls.py
from django.conf.urls.defaults import *
from some_app.views import AboutView
urlpatterns = patterns(’’,
   (r’^about/’, AboutView.as_view()),
)

注意这里的AboutView.as_view()操作,由于AboutView是一个Python类,所以我们使用了继承自TemplateView的as_view()方法代表视图函数。

对于这里显示about.html的需求,我们还可以使用另外一种方法,直接在TemplateView配置中指定要显示的文件路径,比如下面这样:

from django.conf.urls.defaults import *
from django.views.generic import TemplateView
urlpatterns = patterns(’’,
(r’^about/’, TemplateView.as_view(template_name=“about.html”)),
)

如果我们要重定向一个请求,可以使用Django提供的RedirectView,这里就不再介绍了。


from http://bit.ly/JxLVit

Django 自定义标签和过滤器


在Django中,除了默认的标签和过滤器,我们可以使用自定义标签和自定义过滤器。方法是通过{%load %} 来加载自定义标签。比如下面这样:

{% load comments %}

{% comment_form for blogs.entries entry.id with is_public yes %}

上面的例子中 加载了comments标签库,其中包含的comment_form 标签就可以使用了。如果我们要加载多个标签库,可以在它们的名字之间使用空格,比如:

{% load comments i18n %}

需要注意的是,加载的自定义标签是不支持模板继承的。比如,我们定义了一个模板名为“foo.html”其中加载了一个自定义标签库comments.如果我们在定义另一个模板“bar.html”它继承了”foo.html” 这个模板,但是其中的comments标签库却不会被继承下来,不能在“bar.html”模板中使用。


from http://bit.ly/KLUmcK

重载cmd.Cmd的属性


我们不仅可以重载Cmd类的方法,还可以重载它的几个属性。比如 prompt 属性用于配置用户输入的命令提示;intro属性用于显示欢迎信息等。下面是一个例子:

import cmd

class HelloWorld(cmd.Cmd):
    ””“
    Simple command processor example.
    “”“


    prompt = ‘prompt:’
    intro =“Simple command processor example.”

    doc_header = ‘doc_header’
    misc_header = ‘misc_header’
    undoc_header = ‘undoc_header’

    ruler = ’-‘

    def do_prompt(self,line):
        “Change the interactive prompt”
        self.prompt=line+’:’

    def do_EOF(self,line):
        return True


if __name__==’__main__’:
    HelloWorld().cmdloop()

输入一些命令看看效果:

$ python cmd_illustrate_attribute.py

Simple command processor example.
prompt:prompt hello
hello:help

doc_header
—————
prompt

undoc_header
——————
EOF  help

hello:

from http://bit.ly/LKRPgg

重载cmd.Cmd的方法


cmd包下面的Cmd类管理的一个命令行交互环境的整个生命周期,下面是一个例子,我们可以重载了Cmd类的方法来自定义它的行为:

import cmd

class Illustrate(cmd.Cmd):
    ””“
    Illustrate the base class method use.
    “”“

    def cmdloop(self, intro=None):
        print ‘cmdloop(%s)’ % intro
        return cmd.Cmd.cmdloop(self,intro)

    def preloop(self):
        print ‘preloop()’

    def postloop(self):
        print ‘postloop()’

    def parseline(self, line):
        print ‘parseline(%s)=>’ % line,
        ret=cmd.Cmd.parseline(self,line)
        print ret
        return ret

    def onecmd(self, line):
        print ‘onecmd(%s)’%line
        return cmd.Cmd.onecmd(self,line)

    def emptyline(self):
        print ‘emptyline()’
        return cmd.Cmd.emptyline(self)

    def default(self, line):
        print ‘default(%s)’ % line
        return cmd.Cmd.default(self,line)

    def precmd(self, line):
        print ‘precmd(%s)’ % line
        return cmd.Cmd.precmd(self,line)

    def postcmd(self, stop, line):
        print ‘postcmd(%s,%s)’ % (stop,line)
        return cmd.Cmd.postcmd(self,stop,line)

    def do_greet(self,line):
        print ‘hello,’,line

    def do_EOF(self,line):
        “Exit”
        return True

if __name__==’__main__’:
    Illustrate().cmdloop(‘Illustrating the methods of cmd.Cmd’)

其中cmdloop是主要的方法,它相当于一个守护进程一直轮训等待用户的输入。因此,上面重载方法中的preloop和postloop方法是用于在cmdloop之前和之后被调用的方法,每一次cmdloop的轮训都会调用一次onecmd方法,实际的命令行会被传输给parseline方法处理,如果输入一个空的命令行,则emptyline方法会被调用。
下面输入一些命令测试一下:

$ python cmd_illustrate_methods.py

cmdloop(Illustrating the methods of cmd.Cmd)
preloop()
Illustrating the methods of cmd.Cmd
(Cmd) greet Bob
precmd(greet Bob)
onecmd(greet Bob)
parseline(greet Bob)=> (‘greet’, ‘Bob’, ‘greet Bob’)
hello, Bob
postcmd(None,greet Bob)
(Cmd)
precmd()
onecmd()
parseline()=> (None, None, ”)
emptyline()
onecmd(greet Bob)
parseline(greet Bob)=> (‘greet’, ‘Bob’, ‘greet Bob’)
hello, Bob
postcmd(None,)
(Cmd) precmd(EOF)
onecmd(EOF)
parseline(EOF)=> (‘EOF’, ”, ‘EOF’)
postcmd(True,EOF)
postloop()

from http://bit.ly/JTsh22

给cmd命令添加帮助信息


Python中的cmd包用于创建基于命令行的交互环境,并且可以定义自己的命令,我们在前面的例子中已经向大家演示了。下面的例子演示了如何给命令增加帮助信息。比如下面的do_greet方法代表greet命令,那么help_greet方法就代表greet的帮助信息:

import cmd

class HelloWorld(cmd.Cmd):
    ””“
    Simple command processor example.
    “”“

    def do_greet(self,person):
        if person:
            print ‘hi:’,person
        else:
            print ‘hi’

    def help_greet(self):
        print \n.join([‘greet [person]’,
                         ‘Greet the named person’])

    def do_EOF(self,line):
        return True


if __name__==’__main__’:
    HelloWorld().cmdloop()

输入下面的命令测试一下效果:

$ python cmd_do_help.py
(Cmd) help greet
greet [person]
Greet the named person
(Cmd)

from http://bit.ly/KjI2lj

在Django模板中访问对象的方法


Python对象的大多数方法调用都可以在Django模板中直接使用。这意味着我们不只可以调用对象的属性(比如模型的字段属性),还可以调用对象的方法。 比如Django的ORM框架提供了一种“entry_set” 的方法,来获得一个关联对象的集合。假设我们有一个Comment模型,它与一个Task对象关联,一个Task上可能有多个Comment与之关联。这样我们就可以在模板中循环Task关联的Comment并显示出来:

{% for comment in task.comment_set.all %}
  {{ comment }}
{% endfor %}

类似的QuerySets 提供的count()方法也可以被调用来返回集合的数量:

{{ task.comment_set.all.count }}

当然,你也可以直接访问模型对象中的一个自定义方法:

 # In model
class Task(models.Model):
    def foo(self):
        return “bar”

# In template
{{ task.foo }}

不过要注意一点,Django模板语法对于对象方法调用做了一些限制:你不能调用有参数的方法,并在模板中给它传递一个参数。数据应该在视图方法中就完成计算,最后只要把最终的结果传递给模板对象就可以了。


from http://bit.ly/LBXK7m