============================ Django Step by Step (十二) ============================ :作者: limodou :联系: limodou@gmail.com :版本: 0.1 :主页: http://wiki.woodpecker.org.cn/moin/NewEdit :BLOG: http://www.donews.net/limodou :版权: FDL .. contents:: 目录 .. sectnum:: 引言 ===== 如果通讯录中的记录很多,我希望有一种搜索的方法,下面就让我们加一个搜索功能吧。当然,这个搜索功能是很简单的。在 Django_ 邮件列表中看到 WorldOnline(好象是它)有一个搜索的框架,可以定义哪些模块的哪些字段要参加搜索。这样在处理时会自动将相应的信息加入到搜索数据库中进行预处理。现在这个框架并没有开放源码,而且它底层使用的搜索的东西并不是 Django 本身的。这里我只是对姓名字段进行查找。 .. _Django: http://www.djangoproject.com/ 修改 templates/address/address_list.html =========================================== :: [...]
搜索姓名:
{% if has_previous %} [...] 在显示分页的代码上面增加了搜索的处理。 从上面可以看到,条件输入处我增加了一个 ``searchvalue`` 的变量,希望在提交一个搜索后,显示页面的同时显示当前显示时使用的条件。 这里存在一个困难:如何把搜索条件,搜索字符串与通用 view 相关联呢?只要我们生成正确的 queryset(结果集) 即可。但这个结果集需要查询姓名为指定名称的记录,如何实现呢? .. note:: 在以前 ``object_list`` 可以传入 ``extra_lookup_kwargs`` 参数,但后来由于使用了 queryset ,则这个参数不再需要了。 通过 ``urls.py`` 我想是不行的,因为它只从 url 解析,而且对于 QUERY_STRING 是不进行解析的(QUERY_STRING 是指: ``http://example.com/add/?name=test`` 中 ``?`` 后面的东西,也就是 ``name=test`` )。对于搜索条件,我会使用一个 form 来处理, ``method`` 会设为 ``GET`` ,因此生成的 url 中,查询条件正如这个例子,如: ``http://localhost:8000/address/search/?search=limodou`` 。这样无法变成上面所要用到的参数。 因此我决定自定义一个新的 view 方法。 修改 address/views.py ======================= :: from django.views.generic.list_detail import object_list def search(request): name = request.REQUEST['search'] if name: extra_lookup_kwargs = {'name__icontains':name} extra_context = {'searchvalue':name} # return object_list(request, Address, # paginate_by=10, extra_context=extra_context, # extra_lookup_kwargs=extra_lookup_kwargs) return object_list(request, Address.objects.filter(name__icontains=name), paginate_by=10, extra_context=extra_context) else: return HttpResponseRedirect('/address/') 上述代码加到最后去。这里并没有完全重写,而是在 object_list 外面封装了一层,主要是生成要用在 object_list 的中参数。 .. note:: ``extra_context`` 是可以传入到模板中的上下文字典。 .. note:: ``name_icontains`` 是 Django 中过滤条件的写法。这里是说只要包含指定的字符的即可,而且不区分大小写。详细地要看 Django 的 DB-API 文档。 ``request.REQUEST ['search']`` 或者从 GET 或者从 POST 中得到数据,是一个方便的用法。它将得到提交的查询姓名条件,如果存在,则生成 ``extra_lookup_kwargs`` 和 ``extra_context`` 参数,然后按 ``object_list`` 的要求传入。如果没有提交,则回到 address 的起始页面。 修改 address/urls.py ======================= :: from django.conf.urls.defaults import * from newtest.address.models import Address info_dict = { # 'model': Address, 'queryset': Address.objects.all(), } urlpatterns = patterns('', (r'^/?$', 'django.views.generic.list_detail.object_list', dict(paginate_by=10, **info_dict)), (r'^upload/$', 'address.views.upload'), (r'^output/$', 'address.views.output'), (r'^search/$', 'address.views.search'), ) 增加了一个 search 的 url 链接映射。 启动 server 测试 ================= 感觉这个通讯录也差不多了,现在让我们将其部署到 Apache 上去跑一跑吧。 但部署到 apache 时才知道,问题很多啊。主要问题如下: a. 模块名不全 比如许多例子我都是从当前目录(``newtest``)下开始计算,因为在 Windows 下,Python_ 会自动将当前目录加入到 ``sys.path`` 中,因此直接使用 ``address.*`` 之类的不会出错,但在 Apache 下需要使用 ``newtest.address.*`` 这样的方式。必须按教程的方式处理。主要修改 ``urls.py`` 文件。 .. _Python: http://www.python.org/ b. 相对路径的问题 许多使用相对路径的地方都不对了。必须使用绝对路径。不过这一点对于部署来说的确有些麻烦,好在要改动的地方不多,主要在 ``settings.py`` 中。如数据库名字(sqlite3),模板的位置。 其它的就是要注意的地方了。 部署到 Apache 上的体验 ======================= 只能说是体验了,因为我不是 Apache 的专家,也不是 mod_python 的专家,因此下面的内容只能算是我个人的配置记录,希望对大家有所帮助。 安装 mod_python 模块 ~~~~~~~~~~~~~~~~~~~~~~~ Django 对于 Apache 使用 2.X ,对于 mod_python 使用 3.X。安装 mod_python(在windows下)倒是不麻烦。但在 Django 的邮件列表中却有人对于 mod_python 和 Apache 有所讨论,主要的问题是这些改动相对较大,比如说复载,安装需要 root 权限,要重启 Apache 等。这的确是一个要注意的问题,因此有人建议使用 FastCGI 或 SCGI 来处理。 修改 httpd.conf 文件 ~~~~~~~~~~~~~~~~~~~~~~ :: Listen 127.0.0.1:8888 SetHandler python-program PythonPath "['D:/project/svn/limodou/django-stepbystep/newtest'] + sys.path" PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE newtest.settings_apache PythonAutoReload Off PythonDebug On Alias /site_media d:/project/svn/limodou/django-stepbystep/newtest/newtest/media Alias /media C:/Python24/Lib/site-packages/Django-0.91-py2.4.egg/django/contrib/admin/media SetHandler None SetHandler None 这里我使用了虚拟主机(`参考文档`_) 来设置。即使用一台机器,不同的端口来对应不同的服务。主要原因是我希望 Django 的服务可以从 ``/`` 开始,但我还有其它的一些东西要处理,因此不希望对其它的东西有所影响。我没有两个域名,或两个 IP ,因此采用了两个不同的端口。这只是我的一种方式。因为我在本机处理,因此 IP 是 ``127.0.0.1`` 。实际中你应该进行修改。 上面 ``PythonPath`` 主要是将 ``newtest`` 的目录加入到 ``sys.path`` ,以便 Django 可以找到。需要使用绝对路径。 ``SetEvn`` 中设置的 ``DJANGO_SETTINGS_MODULE`` 就对应于你的 项目名.配置文件。因此为了能导入 项目名.配置文件,就需要前面的 ``PythonPath`` 的设置。 .. _`参考文档`: http://www.uplinux.com/download/doc/apache/ApacheManual/vhosts/examples.html ``PythonDebug`` 和 ``PythonAutoReload`` 建议在生产时设为 ``Off`` 。这里我还设了两个别名,用来指向 ``site_media`` 和 ``media`` 目录。 Alias /site_media 是用来将 ``newtest`` 的静态文件设置一个 URL 访问的别名。 Alias /media 是将 Django Admin 的静态文件设置一个 URL 的访问别名。 在 ``site_media`` 和 ``media`` 的 ``Location`` 中设置不进行脚本的解析。 .. note:: 上面的 media 路径是指向 Django Admin 所在的目录。你完全可以将其拷贝出来,这样可能要方便得多。另外在 linux 下使用 ln 也相当的方便。 同时可以注意到 ``settings`` 我改为了 ``settings_apache`` 了。一方面将要把其中的内容有关相对路径的东西改为绝对路径,另一方面我还想保持现在的 ``settings.py`` 。 复制 settings.py 到 settings_apache.py ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 修改 settings_apache.py ~~~~~~~~~~~~~~~~~~~~~~~~~ 将相对路径改为绝对路径。主要有: * ``DATABASE_NAME`` * ``MEDIA_ROOT`` * ``TEMPLATE_DIRS`` * ``STATIC_PATH`` 将 ``DEBUG`` 和 ``TEMPLATE_DEBUG`` 改为 ``False`` 。这样静态文件 serverview 就无效了。这就是为什么上面的 Apache 的配置中要配置 ``site_media`` 的原因。 测试 ~~~~~~ http://localhost:8888/address 更详细的内容请参见 mod_python 文档。关于 admin 的 media 和 template 好象并不需要配置,大家有什么结果可以告诉我。 同时如果你不想每次重启 Apache 来进行测试,可以将:: MaxRequestsPerChild 0 改为:: MaxRequestsPerChild 1 后话 ======= 上面的步骤是直接把开发的东西发布到了 Apache 中去,但实际中开发与运行可能环境根本不一样,最主要可能就是数据库方面的变化,如果model变化,则有可能要编写数据切换程序。许多实际的问题都需要仔细地考虑。