centos下apache+django配置多个网站

之前就已经写过一篇《在linux服务器上部署django项目》,在那篇博文里,我用的操作系统是ubuntu的,而且没有配置域名,直接在一台服务器下放的一个网站,而且用的是mod_wsgi的全局模式。今天的这篇,我将使用mod_wsgi的daemon mode,而且配置多个网站–一个域名对应多个网站。

我的环境:

centos6.7
Apache/2.2.15
python2.7.12
django1.9.7
mod_wsgi4.5.3

本文的前提是环境已经配好了,如果没有配好,可以参考《在linux服务器上部署django项目》。

接下来,以2个django项目,1个php项目为例,进行网站的配置。

2个django项目的地址:

/mywebsite/django1
/mywebsite/django2

php项目的地址

/mywebsite/myphp

使用mod_wsgi的daemon mode

这个例子,我们将第一个django项目配置到服务器上,使用mod_wsgidaemon mode

对应的httpd.conf文件应该这么写:

<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django1 python-path=/mywebsite/django1
     WSGIProcessGroup django1
     WSGIScriptAlias / /mywebsite/django1/yourproject/wsgi.py   #在 /mywebsite/django1 下,project和app在同一级目录
    <Directory /mywebsite/django1/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>

   #别忘了静态文件配置,这个和一般的php项目是类似的
    Alias /static "/your/path/collectedstatic"
    <Directory "/your/path/collectedstatic">
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

但是据测试,有时候可能会出现错误,在log里面提示如下:

Permission denied: mod_wsgi (pid=10458): Unable to connect to WSGI daemon process ‘lookfor404’ on ‘/etc/httpd/logs/wsgi.10453.0.1.sock’ as user with uid=11.

逛了半天的stackoverflow,最终看到一个靠谱的答案提到这个网址,
https://code.google.com/archive/p/modwsgi/wikis/ConfigurationIssues.wiki#Location_Of_UNIX_Sockets

解决方法就是,在virtualhost外面加多一句
WSGISocketPrefix /var/run/wsgi

一个域名对应多个网站

接下来,看看怎么用一个域名配置多个网站。

比如,我想要的效果是这样的:访问lookfor404.com/django1,进入django1这个项目;访问lookfor404.com/django2,进入django2这个项目;访问lookfor404.com/myphp,进入myphp这个项目。同样的,直接看配置文件。为了看起来清楚,我把静态文件设置先忽略了。

#----------django1项目配置
<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django1 python-path=/mywebsite/django1
     WSGIProcessGroup django1
     #注意,以下发生变化,即第二个参数为访问的路径
     WSGIScriptAlias /django1 /mywebsite/django1/yourproject/wsgi.py   
    <Directory /mywebsite/django1/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>
</VirtualHost>

#----------django2项目配置
<VirtualHost *:80>
     ServerName lookfor404.com           # 域名 
     WSGIDaemonProcess django2 python-path=/mywebsite/django2
     WSGIProcessGroup django2
     #如下,即访问url为lookfor404.com/django2
     WSGIScriptAlias /django2 /mywebsite/django2/yourproject/wsgi.py   
    <Directory /mywebsite/django2/yourproject>
       <Files wsgi.py>
          Order Deny,Allow
          Allow from All
       </Files>
    </Directory>
</VirtualHost>

#----------myphp项目配置
<VirtualHost *:80>
     ServerName lookfor404.com   # 域名 
     DocumentRoot /mywebsite/myphp
     <IfModule alias_module>
          #设置访问url为lookfor404.com/myphp
          Alias /myphp "/mywebsite/myphp"
         <Directory "/mywebsite/myphp">
          AllowOverride all
          Order allow,deny
          Allow from all
         </Directory>
      </IfModule>
</VirtualHost>

总结来说,这种配置适用于你只有一个域名,而你有多个网站程序,而且你不使用子域名。对于django项目,通过WSGIScriptAlias的第一个参数就可以设定访问的域名子路径了,对于php项目,使用Alias即可解决问题。

另外,多个域名多个网站这种情况就不说了,直接在servername里设置就行。

django项目出现WSGI Bad Bad Request (400) 错误

最后还要说一下这个错误,明明之前一切配置都顺利,用ip访问也没问题,但是一用域名访问就出错了,原来是新版django的问题,需要到setting.py里面设置可访问的域名:

ALLOWED_HOSTS = [
‘lookfor404.com’, # 只允许主域名
‘.lookfor404.com’, # 允许主域名以及子域名
‘.lookfor404.com.’, # 允许FQDN以及子域名
]

然后重启一下apache就行了。

 

运行ggplot出现问题:no display name and no $DISPLAY environment variable

最近在用django做一个项目,关于数据可视化的。作图方面,之前用过百度的echart,这个是在前端直接调用的,这次想尝试在后台直接生成图,然后存在服务器上,之后前端再把图片显示出来就好了。

用的ggplot。

在windows下,用runserver测试,没问题。但是在服务器上,就跑不了了,出现了这样的提示:

tkinter.TclError: no display name and no $DISPLAY environment variable

查看了一下debug信息,发现貌似和Matplotlib有关,继续顺藤摸瓜。

找到了问题所在:http://matplotlib.org/faq/howto_faq.html#howto-webapp

官网的英文解释:

Many users report initial problems trying to use maptlotlib in web application servers, because by default matplotlib ships configured to work with a graphical user interface which may require an X11 connection. Since many barebones application servers do not have X11 enabled, you may get errors if you don’t configure matplotlib for use in these environments. Most importantly, you need to decide what kinds of images you want to generate (PNG, PDF, SVG) and configure the appropriate default backend. For 99% of users, this will be the Agg backend, which uses the C++ antigrain rendering engine to make nice PNGs

不想读完也没关系,大概说下怎么回事。

不同的系统有不同的用户图形接口,默认的接口在windows下跑是没有问题的,问题是我们很多的webapp都不在windows上跑,一般在linux上面,所以要更改它的默认配置,把模式更改成Agg。

纯代码解决方案

这也是大部分人在网上诸如stackoverflow的问答平台得到的解决方案,在引入pyplot、pylab之前,要先更改matplotlib的后端模式为”Agg”。直接贴代码吧!

# do this before importing pylab or pyplot
Import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot asplt

更改配置文件方案

就我的情况而言,上面那种解决方案似乎不适用,因为我是在django中使用的ggplot,它调用matplotlib的时机,我并不是很清楚。所以试了几次,都没有能把matplotlib.use('Agg')这句代码放在正确的位置上,因而也解决不了错误。

所以我转向了另一种解决方案,也是从官网启发而来。

好了,这里告诉我们,什么是backend:

http://matplotlib.org/faq/usage_faq.html#what-is-a-backend

然后这里告诉我们,怎么改配置文件:

http://matplotlib.org/users/customizing.html#customizing-matplotlib

看到下面这个地方:

matplotlibrc文件

没错,它的配置文件就是matplotlibrc,在哪里呢?不同系统不一样,我的系统是ubuntu,运行了命令whereis matlotlibrc,找到了。

matplotlibrc文件位置

编辑一下:

sudo vim /etc/matplotlibrc

找到backend这里,然后将其改成Agg,如下!

# The default backend; one of GTK GTKAgg GTKCairo GTK3Agg GTK3Cairo
# CocoaAgg MacOSX Qt4Agg Qt5Agg TkAgg WX WXAgg Agg Cairo GDK PS PDF SVG
# Template.
# You can also deploy your own backend outside of matplotlib by
# referring to the module name (which must be in the PYTHONPATH) as
# ‘module://my_backend’.
backend : Agg

保存,运行,错误消失。

django中的Q()函数:应用于model数据查询的与(and)或(or)操作

问题背景

之前用django的时候,数据库这一块也没有涉及到比较复杂一点的查询,一般就是一个filter()或者一个get()就搞定了,前几天做一个可视化的项目时,遇到了多条件复合查询,看了下文档,django的orm还是挺好用的,Q()函数可以解决这个问题。

比如我要查询id为1或者id为2的一个数据,在filter里面,是不能够这么直接来的:filter(id=1,id=2),只能使用Q函数。为了更深入地理解Q函数,我参考官方文档,整理一下它的用法。

文档位置:https://docs.djangoproject.com/en/1.9/topics/db/queries/#complex-lookups-with-q-objects

django中Q()函数的介绍

如果你需要进行复杂的查询(比如or条件),你可以使用Q对象。

Q对象是用来封装查询参数的,比如,它可以仅仅用来封装单独一个like查询:

from django.db.models import Q
Q(question__startswith='What')

Q函数可以通过逻辑符号连接

Q对象可以和&|这两个符号一起来使用,即and和or。下面这个例子就用or将两个查询组合在了一起:

Q(question__startswith='Who') | Q(question__startswith='What')

相当于以下sql语句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

另外,还可以使用非符号~,比如:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Q函数用于数据库查询

以上介绍了Q的组合方法,那么怎么把它应用到数据库的查询呢?一般而言,可以把它们放到filter(),get()或者exclude()里面,比如:

Poll.objects().filter(Q(question__startswith='Who') | ~Q(pub_date__year=2005))

Q函数和关键字参数混合使用

另外,Q对象还可以和关键字参数一起使用,不过Q一定要放在前面,以下是正确例子:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

相当于sql查询语句如下:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

关键字参数放在前面是错误的用法!!如下是错误的!

# 错误用法
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

我的实践

我喜欢这样来用Q对象。先在外面将条件组合好,然后再传入filter()get()或者exclude()里面,代码片段如下:

from django.db.models import Q
my_filter = Q()
my_filter = my_filter | Q(id=1)
my_filter = my_filter | Q(name="lipengfei")
result = People.objects.filter(my_filter)