1.3.12 第十二讲 搜索和部署
1 引言
如果通讯录中的记录很多,我希望有一种搜索的方法,下面就让我们加一个搜索功能吧。当然,这个搜索功能是很简单的。在 第九讲介绍过的generic view
来显示结果,因为列表页面的处理非常简单:
class IndexView(generic.ListView):
model = Address
template_name = 'address/list.html'
paginate_by = 2
但是这里存在一个困难:如何把搜索条件,搜索字符串与generic view 相关联呢?通过 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
。这样无法变成上面所要用到的参数。
这里我们需要对generic view进行一下扩充,我们需要实现get_queryset
和get_context_data
这两个方法。分别用来指定结果集和模板渲染的参数,我们先来看看新的view方法怎么写:
3 修改 address/views.py
class SearchView(generic.ListView):
template_name = 'address/list.html'
paginate_by = 2
def get_queryset(self):
if self.request.GET.get('search'):
self.name = self.request.GET['search']
return Address.objects.filter(name = self.name)
else:
self.name = None
return Address.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.name:
context['searchvalue'] = self.name
return context
我们使用get_queryset
方法代替了model = Address
,这样可以更加灵活的定义返回的结果集。
我们使用get_context_data
指定了可以传入到模板中的上下文字典。
self.request.GET['search']
从 GET 中得到数据,是一个方便的用法。它将得到提交的查询姓名条件,如果有这个参数,那么我们使用filter
函数对结果进行过滤。如果没有提交,则显示全部数据。
4 修改 address/urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', helloworld.index),
url(r'^add/$', add.index),
url(r'^list/$', list.index),
url(r'^xls/(?P<filename>\w+)/$', xls_test.output),
url(r'^login/$', login.login),
url(r'^logout/$', login.logout),
url(r'^wiki/', include('wiki.urls')),
url(r'^address/', include('address.urls')),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
增加了一个 search 的 url 链接映射。
5 启动 server 测试
感觉这个通讯录也差不多了,现在让我们将其部署到 Apache 上去跑一跑吧。
但部署到 apache 时才知道,问题很多啊。主要问题如下:
- CentOS 7服务器默认自带的Python版本太低
CentOS 7自带的Python版本为Python2.7,我们希望能够使用最新的Python 3.6
相对路径的问题
许多使用相对路径的地方都不对了。必须使用绝对路径。不过这一点对于部署来说的确有些麻烦,好在要改动的地方不多,主要在 settings.py 中。如数据库名字(sqlite3),模板的位置。
其它的就是要注意的地方了。
6 部署到 Apache 上的体验
只能说是体验了,因为我不是 Apache 的专家,也不是 mod_wsgi 的专家,因此下面的内容只能算是我个人的配置记录,希望对大家有所帮助。
6.1 服务器安装Python 3.6
下面的操作我们都假定环境是CentOS 7的环境,您可以在阿里云、腾讯云等公有云服务商购买ECS服务器,会自动给你安装好相应的操作系统,最后给你一个root的用户名和密码。
使用你自己熟悉的SSH环境,用root用户登录即可,首先安装Python 3.6,执行下面的命令。
yum install -y python36
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python36 get-pip.py
pip install virtualenv
这样的话你安装的pip会默认使用Python3.6,我们顺手安装好了virtualenv环境。操作系统的Python环境不要安装太多的库文件,都放到自己应用的venv环境中,创建一个虚拟的环境。
6.2 安装 mod_wsgi 模块
mod_wsgi的安装有很多种方法,这里介绍的是官方推荐的办法,使用pip安装,首先需要安装http的开发包,然后使用pip安装mod_wsgi到系统的lib库中,执行下面的命令。
yum install -y http-devel python36-devel
pip install mod_wsgi
然后我们需要将mod_wsgi安装到apache服务器module中去。
cd /etc/httpd/modules
ln -s /usr/lib64/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so mod_wsgi.so
我们通过在/etc/httpd/modules
下面创建符号链接的方式,让apache在启动的时候自动加载mod_wsgi.so。
然后我们需要在/etc/httpd/conf.modules.d
中创建一个文件,加载mod_wsgi.so,使用vi /etc/httpd/conf.modules.d/10-wsgi.conf
命令创建配置文件,然后录入下面的内容:
LoadModule wsgi_module modules/mod_wsgi.so
之后使用systemctl restart httpd
重启apache服务即可。
6.2 创建配置文件
假定我们的django工程在/var/www/proc/newtest,那么我们应该创建/etc/httpd/conf.d/wsgi.conf
WSGIScriptAlias /newtest /var/www/proc/newtest/newtest/wsgi.py process-group=newtest
WSGIPythonHome /var/www/proc/newtest/venv
WSGIPythonPath /var/www/proc/newtest
<Directory /var/www/proc/newtest/newtest>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
#Deamon模式设置
WSGIDaemonProcess newtest python-home=/var/www/proc/newtest/venv python-path=/var/www/proc/newtest
WSGIProcessGroup newtest
#静态文件
Alias /newtest/robots.txt /var/www/proc/newtest/static/robots.txt
Alias /newtest/favicon.ico /var/www/proc/newtest/static/favicon.ico
Alias /newtest/media/ /var/www/proc/newtest/media/
Alias /newtest/static/ /var/www/proc/newtest/static/
<Directory /var/www/proc/newtest/static>
Require all granted
</Directory>
<Directory /var/www/proc/newtest/media>
Require all granted
</Directory>
WSGIPythonHome
是Python运行环境的绝对路径,这里指向我们virtualenv的目录
这里我还设了两个别名,用来指向 media
和 static
目录。在 media
和 static
的 Location
中设置不进行脚本的解析。
上面的 media 路径是指向 Django 在 Python 上的安装目录。你完全可以将其拷贝出来,这样可能要方便得多。另外在 linux 下使用 ln 也相当的方便。
6.3 测试
更详细的内容请参见 mod_wsgi 文档。关于 admin 的 media 和 template 好象并不需要配置,大家有什么结果可以告诉我。
同时如果你不想每次重启 Apache 来进行测试,可以将:
MaxRequestsPerChild 0
改为:
MaxRequestsPerChild 1
7 后话
上面的步骤是直接把开发的东西发布到了 Apache 中去,但实际中开发与运行可能环境根本不一样,最主要可能就是数据库方面的变化,如果model变化,则有可能要编写数据切换程序。许多实际的问题都需要仔细地考虑。