Static 和 Templates 的文件结构

在 Django 中,推荐把每一个 APP 所需要的 static 和 templates 都放在 APP 自己的文件夹目录下面,这样非常方便 APP 的移植。

这样的结构虽然方便,但是存在一个问题,就是当 templates 调用 static 文件时,会出现资源重复。比如 app1 和 app2 下都有 css/main.css 文件,则在 templates 中使用 {% static 'css/main.css' %} 时,就会不知道该使用哪一个 main.css

为了解决上述状况,可以采用在每一个 app_name/static 文件夹下面,添加一层 app_name 的方式,就非常优雅的解决了上述问题。文件夹结构示例如下:

Project
│ 
├── app1
│   ├── static
│   │   └── app1
│   └── templates
│       └── app1
├── app2
│   ├── static
│   │   └── app2
│   └── templates
│       └── app2
└── app3
    ├── static
    │   └── app3
    └── templates
        └── app3

当使用上述文件夹结构式,可以通过 {% static 'app1/css/main.css' %}{% static 'app1/css/main.css' %} 的方式,来分别调用不同 app 下的文件

静态文件部署

当 Django 做正式线上部署是,设置 DEBUG=False 后,会发现找不到 static 文件的情况。有两种解决方案,一是使用 Nginx 等 Webserver 做转发,二是使用whitenoise 这个 python 包来做静态文件的服务。两种方案分别如下:

Nginx 转发

做 Nginx 转发,需要做以下几件事情:

  1. 先设定 STATIC_ROOTSTATICFILES_DIRS

    STATIC_ROOT = '/var/www/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, "app1/static"),
        os.path.join(BASE_DIR, "app2/static"),
    ]
    
  2. 将所有 Static 文件,拷贝至 Static 文件夹 python manage.py collectstatic

  3. 设置 Nginx 转发

    server {
        listen 80;
        server_name _;
           
        location /static/ {
            alias /var/www/static/;
        }
           
        location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass http://127.0.0.1:8000;
        }
    }
    

使用 whitenoise

使用 whitenoise 时,前两个步骤和设置 Nginx 时时一致的

  1. 设定 STATIC_ROOTSTATICFILES_DIRS

    STATIC_ROOT = os.path.join(BASE_DIR, "static")
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, "app1/static"),
        os.path.join(BASE_DIR, "app2/static"),
    ]
    
  2. 生成 Static 文件夹 python manage.py collectstatic

  3. 添加 Middleware

    注意添加位置一定在 SecurityMiddleware 之后,其他的 Middleware 之前

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware',
        ...
    ]
    
  4. 去掉 Debug 模式,并验证 python manage.py runserver