【兰山问题】Django中的静态文件

项目部署到阿里云(nginx+uwsgi)上后,静态文件加载没有问题。但是在本地,使用开发服务器,却始终加载不成功。

settings\common.py:
STATIC_ROOT = os.path.join(BASE_DIR, 'xxx/yyy/static/')

#STATICFILES_FINDERS = (
#    'django.contrib.staticfiles.finders.FileSystemFinder',
#    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
#)

INSTALLED_APPS = [
    #'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sites',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    ...
]
STATICFILES_DIRS = [
#    os.path.join(BASE_DIR, 'xxx/yyy/static'),
]
STATIC_URL = '/static/'
settings\dev.py:
from .common import *
#是否注释STATICFILES_FINDERS,对runserver --nostatic情况下,加载静态文件没有任何影响,都可以正常显示;
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

#STATICFILES_FINDERS = (
#    'django.contrib.staticfiles.finders.FileSystemFinder',
#    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
#)
settings\prod.py:
from .common import *
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    #Added at 20170428 开发环境下,如果注释掉,无法正确加载静态文件
    #urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

执行python manage.py runserver

浏览器输入http://127.0.0.1:8000/ 后,可见各种静态文件没有正确加载。

【兰山问题】Django中的静态文件_第1张图片
Paste_Image.png

浏览器Dev模式下,显示404错误。
【兰山问题】Django中的静态文件_第2张图片
Paste_Image.png

浏览器输入 http://127.0.0.1:8000/static/site/v1/img/LOGO.PNG 后,显示同样的错误404。
【兰山问题】Django中的静态文件_第3张图片
Paste_Image.png

执行python manage.py runserver --nostatic

浏览器输入http://127.0.0.1:8000/ 后,各种静态文件正确加载。


【兰山问题】Django中的静态文件_第4张图片
Paste_Image.png
【兰山问题】Django中的静态文件_第5张图片
Paste_Image.png

浏览器输入http://127.0.0.1:8000/static/site/v1/img/LOGO.PNG 后,可以正确加载。

静态文件

生产环境

静态文件交由Web Server处理,Django本身不处理静态文件。简单的处理逻辑如下(以nginx为例):
URI请求 --->>> Web Server
按照Web Server里面的配置规则处理(以nginx为例,主要配置在nginx.conf里面的location参数。),如果是静态文件,则由nginx直接处理;如果不是,则交由Django处理,Django会根据urls.py里面的规则进行匹配。

开发环境

以上是部署到Web服务器后的处理方式,为了便于开发,Django提供了在开发环境下对静态文件的处理机制,方法是这样的(可能是低版本的步骤,仅供理解用,步骤谨慎怀疑):
1.在INSTALLED_APPS里面加入'django.contrib.staticfiles';
2.在urls.py里面加入:

if settings.DEBUG:  
   urlpatterns += patterns('', url(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),   
        url(r'^static/(?P.*)$','django.views.static.serve',{'document_root':settings.STATIC_ROOT}), )

3.这样就可以在开发阶段直接使用静态文件了。

MEDIA_ROOT和MEDIA_URL

静态文件的处理包括STATIC和MEDIA两类,这往往容易混淆,在Django里面是这样定义的:
MEDIA指用户上传的文件,比如在Model里面的FileField、ImageField上传的文件。如果你定义MEDIA_ROOT=C:\temp\media,那么File = models.FileField(upload_to='abc/'),上传的文件就会被保存到C:\temp\media\abc
举个例子:

class blog(models.Model):  
       Title=models.charField(max_length=64)  
       Photo=models.ImageField(upload_to="photo")

上传的图片就是上传到c:\temp\media\photo,而在模板中要显示该文件,则这样写{{MEDIA_URL}}blog.Photo
在settings里面设置的MEDIA_ROOT必须是本地路径的绝对路径,一般是这样写,

PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))  
MEDIA_ROOT=os.path.join(PROJECT_PATH,'media/').replace('\\','/') 

MEDIA_URL 是指从浏览器访问时的地址前缀,举个例子:

MEDIA_ROOT=c:\temp\media\photo  
MEDIA_URL="/data/"                     #可以随便设置  

在开发阶段,media的处理由Django处理:访问http://localhost/data/abc/a.png 就是访问 c:\temp\media\photo\abc\a.png,在模板里面这样写({{MEDIA_URL}}abc/a.png),在部署阶段最大的不同在于你必须让web服务器来处理media文件,因此你必须在web服务器中配置,以便能让web服务器访问media文件。
以nginx为例,可以在nginx.conf里面这样写:

 location ~/media/{
   root   /temp/  
   break;
}

具体可以参考如何在nginx部署Django的资料。

STATIC_ROOT和STATIC_URL

STATIC主要指的是如css、js、images这样的文件,在settings里面可以配置STATIC_ROOTSTATIC_URL配置方式与MEDIA_ROOT是一样的,但是要注意STATIC_ROOTMEDIA_ROOT位置不能一样。
STATIC文件一般保存在以下位置:

  1. STATIC_ROOT:在settings里面设置,一般用来放一些公共的js,css,image等。
  2. APP的static文件夹,在每个APP所在文件夹中可以建立一个static文件夹,然后当运行collectstatic时,Django会遍历INSTALL_APPS里面所有APP的static文件夹,将里面所有的文件复制到STATIC_ROOT。因为,如果你要建立可复用的APP,那么你要将该APP所需要的静态文件放在static文件夹中。
    也就是说一个项目引用了很多app,那么这个项目所需要的css, images等静态文件是分散在各个app的static文件的,比较典型的是admin应用。当你要发布时,需要将这些分散的static文件收集到一个地方就是STATIC_ROOT
  3. STATIC文件可以配置STATICFILES_DIRS,用以指定额外的静态文件存储位置。
    STATIC_URL的含义与MEDIA_URL类似。
    如果在部署阶段找不到css,js,则可能是一下几个问题:
    1.web服务器配置有问题,不同的部署方式对静态文件的处理有所不同;
    2.没有运行collectstatic将所需要的静态文件收集到STATIC_ROOT

MEDIA_ROOT : 主要是为了存放上传的文件,比如在ImageField中,这个值加上upload_to的值就是真实存放上传图片的文件位置;
Django里,文件内容实际上是不会存放到数据库里边的,大多数数据库存放效率低,需要保存在文件系统里。
MEDIA_URL : URL的映射,前后要加上"/"表示从根目录开始,比如"/site_media/",加上这个属性之后,静态文件的链接前面会加上这个值。
STATIC_ROOT :这个文件里面的目录会当成静态文件处理。

STATIC_URL : URL映射,指定静态目录的URL,默认是"/static/"

STATICFILES_DIRS :指定一个工程里边哪个目录存放了与这个工程相关的静态文件,是一个列表。如果列表中有一个是“/home/shishang/test/static”,其中有一个文件内容是productlist.html,我们只要访问http://localhost:8000/static/productlist.html就可以直接访问了。

Django提供了一个方法自动地将所有的静态文件放在一起。只要在写App的时候创建一个static子目录专门保存静态文件就行了。在开发阶段,不必费心去做映射,不需要配置urls.py。在部署到生产环境的时候,只需要配置Apache/static/映射到STATIC_ROOT,然后运行manage.py collectstatic,自动地STATICFILES_DIR列出的目录以及各个APP下的static子目录的所有文件复制到STATIC_ROOT。因为复制过程可能会覆盖掉原来的文件,所以,一定不能把我们辛苦做出来静态文件放这边!在开发阶段,Django把/static映射到django.contrib.staticfiles这个APP。staticfiles自动地从STATICFILES_DIRSSTATIC_ROOT以及各个App子目录里面搜索静态文件。一旦部署到开发环境上,settings.py不需要重新编写,只要在Apache的配置文件里面写好映射,/static将会被Apache处理。django.contrib.staticfiles虽然仍然存在,但因为不会接收到以/static/开始的路径,所以将不会产生作用。不必担心Django会使处理速度变慢。另外,当settings.DEBUG is False的时候,staticfiles将自动关闭。

内部是怎么工作的?

  1. 首先,检索settings.py中所有关于静态文件的设置,它们是STATIC_URL,STATIC_ROOT, STATICFILES_FINDERS, STATICFILES_DIRS
  2. 同样我们已经将'django.contrib.staticfiles'添加进了INSTALLED_APPS
  3. 现在先不管STATIC_ROOTSTATICFILES_DIRS。即使你将它们注释或者删除,你的项目依然能够像想在一样工作。
  4. 我们需要将'django.contrib.statifiles'添加进INSTALLED_APPS,如果我们想要使用Django默认的静态文件处理服务。
  5. 所谓Django默认的静态文件处理服务就相当于需要使用Django提供的python manage.py runserver
  6. Django默认在STATIC_URL下处理静态文件。注意STATIC_URL已经设置为‘/static/’。这就是为什么我们获取到了我们的静态文件,举个例子,样式文件在这个url下http://127.0.0.1:8000/static/style.css。
    如果你访问 http://127.0.0.1:8000/static_changed/styles.css ,你将会得到一个404页面。如果你想要在 http://127.0.0.1:8000/static_changed/styles.css提供, 需要设置 STATIC_URL = '/static_changed/'。现在动手试试吧。这只是为了举例说明STATIC_URL的用处,现在都改回默认设置,即 STATIC_URL = '/static/'
  7. 下一个问题是,Django是怎么知道从哪里去去读取静态文件的,或者说怎么知道去哪里找到静态文件呢?这就是STATICFILES_FINDERS的作用了。
    STATICFILES_FINDERS中我们有两条记录:
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder

现在你可以先不管FileSystemFinder,如果你愿意,你可以先注释掉这一行。AppDirectoriesFinder告诉Django从INSTALLED_APPS中每一个app下的static/子目录下去寻找静态文件。记住,我们是将style.css放在了some_appstatic/子目录下,这就是为什么Django能够找到它,并且进行正确的处理。如果你将'/static/'子目录修改为其它名字,你的静态文件就不能被正确处理了。动手试一试吧。注释掉 AppDirectoriesFinder 这一行,然后访问 http://127.0.0.1:8000/static/styles.css ,现在样式文件不能被正确地处理了。好,尝试过后去掉注释。
现在,我们知道了STATIC_URLSTATICFILES_FINDERS的作用。我们现在仍然不需要用到STATIC_ROOTSTATICFILES_DIRS

这里发生了什么?

  1. Django服务器收到一个关于静态文件的请求,应该是一个以'/static/'开头的url。
  2. 它开始在STATICFILES_DIRS设定的所有目录中寻找这个静态文件,比如base.css
  3. 由于我们在STATICFILES_DIRS中指定了一个目录,即project_static,Django服务器在这个目录中尝试寻找这个文件。它在这个目录中进行搜索时找到了这个文件,然后进行处理。
  4. 如果没有在STATICFILES_DIRS指定的目录中找到这个文件,它将会在INSTALLED_APPS下所有app的static/子目录尝试寻找。
    注意,这时候依然不需要添加staticfiles_urlpatterns()

关于STATIC_ROOT

  1. 如果在开发阶段使用Djangorunserver,你将永远不会需要STATIC_ROOT
  2. 一旦你需要进入生产,你能在服务器中使用它。Django提供了一个静态文件管理的命令叫做collectstatic,它将收集所有的静态资源,(如在STATICFILES_DIRS中找到的和在所有app下的static/子目录中找到的静态资源),将它们放进一个STATIC_ROOT定义的位置。
    STATIC_ROOT只有你在使用collectstatic命令的时候才会有用处。

Refer to:

  1. http://blog.csdn.net/fighter_yy/article/details/41249033
  2. http://www.tuicool.com/articles/BjIBJi
  3. http://lanceverw.iteye.com/blog/1798037

settings

Django的STATICFILES_FINDERS设置项是一个列表,它包含了若干个知道如何从不同地点寻找静态文件的搜寻器。其中之一是AppDirectoriesFinder,它会从INSTALLED_APPS中各个应用的'static'子目录中寻找文件。

STATICFILES_FINDERS

Default:
[
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]

The list of finder backends that know how to find static files in various locations.
The default will find files stored in the STATICFILES_DIRS setting(using django.contrib.staticfiles.finders.FileSystemFinder) and in a static subdirectory of each app(using django.contrib.staticfiles.finders.AppDirectoriesFinder). If multiple files with the same name are present, the first file that is found will be used.
One finder is disabled by default:
django.contrib.staticfiles.finders.DefaultStorageFinder. If added to your STATICFILES_FINDERS settings, it will look for static files in the default file storage as defined by the DEFAULT_FILE_STORAGE setting.
Refer: https://docs.djangoproject.com/en/1.11/ref/settings/

STATICFILES_STORAGE

Default: 'django.contrib.staticfiles.storage.StaticFilesStorage'
The file storage engine to use when collecting static files with the collectstatic management command.
A ready-to-use instance of the storage backend defined in this setting can be found at django.contrib.staticfiles.storage.staticfiles_storage.

The staticfiles app

django.contrib.staticfiles collects static files from each of your appliations(and any other places you specify) into a single location that can easily be served in production.
For an introduction to the static files app and some usage examples, seeManaging static files (e.g. images, JavaScript, CSS). For guidelines on deploying static files, see Deploying static files.

Management Commands

django.contrib.staticfiles exposes three management commands.

collectstatic

django-admin collectstatic
Collects the static files into STATIC_ROOT.
Duplicate files names are by default resolved in a similar way to how template resolution works: the file that is the first found in one of the speicified locations will be used. If you're confused, the findstatic command can help show you which files are found.
On subsequent collectstatic runs(if STATIC_ROOT isn't empty),files are copied only if they have a modified timestamp greater than the timestamp of the file in STATIC_ROOT. Therefore if you remove an application from INSTALLED_APPS, it's a good idea to use the collectstatic --clear option in order to remove stale static files.
Files are searched by using the enabled finders. The default is to look in all locations defined in STATICFILES_DIRS and in the 'static' directory of apps specified by the INSTALLED_APPS setting.
The collectstatic management command calls the post_process() method of the STATICFILES_STORAGE after each run and passes a list of paths that have been found by the management command. It also receives all command line options of collectstatic. This is used by the CachedStaticFileStorage by default.
For a full list of options, refer to the commands own help by running:

$python manage.py collectstatic --help

findstatic

django-admin findstatic staticfile [staticfile ...]

Searches for one or more relative paths with the enabled finders.
For example:

$ python manage.py findstatic css/base.css admin/js/core.js
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Found 'admin/js/core.js' here:
  /home/polls.com/src/django/contrib/admin/media/js/core.js

findstatic --first
By default, all matching locations are found. To only return the first match for each relative path, use the --first option:

$ python manage.py findstatic css/base.css --first
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css

This is a debugging aid; it’ll show you exactly which static file will be collected for a given path.
By setting the --verbosity flag to 0, you can suppress the extra output and just get the path names:

$ python manage.py findstatic css/base.css --verbosity 0
/home/special.polls.com/core/static/css/base.css
/home/polls.com/core/static/css/base.css

On the other hand, by setting the --verbosity flag to 2, you can get all the directories which were searched:

$ python manage.py findstatic css/base.css --verbosity 2
Found 'css/base.css' here:
  /home/special.polls.com/core/static/css/base.css
  /home/polls.com/core/static/css/base.css
Looking in the following locations:
  /home/special.polls.com/core/static
  /home/polls.com/core/static
  /some/other/path/static

runserver

django-admin runserver [addrport]

Overrides the core runserver command if the staticfiles app is installed and adds automatic serving of static files and the following new options.

--nostatic

User the --nostatic option to disable serving of static files with the statifiles app entirely. This option is only available if the staticfiles app is in your project's INSTALLED_APPS setting.
Example usage:

django-admin runserver --nostatic

Storages存储

StaticFilesStorage

class storages.StaticFilesStorage

A subclass of the FileSystemStorage storage backend that uses the STATIC_ROOT setting as the base file system location and the STATIC_URL setting respectively as the base URL.
storage.StaticFilesStorage.post_process(paths, **options)
This method is called by the collectstatic management command after each run and gets passed the local storages and paths of found files as a dictionary, as well as the command line options.

Other Helpers

There are a few other helpers outside of the staticfiles app to work with static files:

  1. The django.template.context_processors.static()```` context processor which addsSTATIC_URLto every template context rendered withRequestContext``` contexts.
  2. The builtin template tag static which takes a path and url joins it with the static prefix STATIC_URL. If django.contrib.staticfiles is installed, the tag uses the url() method of the STATICFILES_STORAGE instead.

Static file development view静态文件开发视图

The static files tools are mostly designed to help with getting static files successfully deployed into production.
静态文件工具主要用于帮助将静态文件成功部署到生产环境中。
This usually means a separate, dedicated static file server, which is a lot of overhead to mess with when developing locally.
这通常意味着一个单独的,专用的静态文件服务器,这在本地开发时是很麻烦的开销。
Thus, the staticfiles app ships with a quick and dirty helper view that you can use to serve files locally in development.
因此,staticfiles应用程序附带了一个快速和脏的帮助视图,可以使用它在开发中本地提供文件。

views.serve(request, path)

views.serve(request, path)

This view function serves static files in development. This view will only work if DEBUG is True. That's because this view is grossly inefficient and probably insecure. This is only intended for local development, and should never be used in production.
This view is automatically enabled by runserver (with a DEBUG
setting set to True). To use the view with a different local development server, add the following snippet to the end of your primary URL configuration:

from django.conf import settings
from django.contrib.staticfiles import views

if settings.DEBUG:
    urlpatterns += [
        url(r'^static/(?P.*)$', views.serve),
    ]

Note, the beginning of the pattern (r'^static/') should be yourSTATIC_URL setting.

urls.staticfiles_urlpatterns()

urls.staticfiles_urlpatterns()

This will return the proper URL pattern for serving static files to your already defined pattern list. Use it like this:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

# ... the rest of your URLconf here ...

urlpatterns += staticfiles_urlpatterns()

This will inspect your STATIC_URL setting and wire up the view to serve static files accordingly. Don’t forget to set the STATICFILES_DIRS setting appropriately to let django.contrib.staticfiles know where to look for files in addition to files in app directories.

Refer to: https://docs.djangoproject.com/en/1.11/ref/contrib/staticfiles/

Managing static files(e.g. images,JS,CSS)

Websites generally need to serve additional files such as images, JavaScript, or CSS. In Django, we refer to these files as 'static files'. Django provides django.contrib.staticfiles to help you manage them.

Configuring static files

  1. Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS.
  2. In your settings file, define STATIC_URL, for example:
STATIC_URL = '/static/'
  1. In your templates, either hardcode the url ike /static/my_app/example.jpg or, preferably, use the static template tag to build the URL for the given relative path by using the configured STATICFILES_STORAGE storage(this makes it much easier when you want to switch to a content delivery network(CDN) for serving static files).
{% load static %}
![]({% static )
  1. Store your static files in a folder called static in your app. For example, my_app/static/my_app/example.jpg

In addition to these configuration steps, you will also need to actually serve the static files.
During development, if you use django.contrib.staticfiles, this will be done automatically by runserver when DEBUG is set to True(see django.contrib.staticfiles.views.serve()).
This method is grossly inefficient and probably insecure, so it is unsuitable for production.

Your project will probably also have static asserts that aren't tied to a particular app. In addition to using a static/ directory inside your apps, you can define a list of directories(STATICFILES_DIRS) in your settings files where Django will also look for static files. For example:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    '/var/www/static/',
]

Serving static files during development

If you use django.contrib.staticfiles as explained above, runserver will do this automatically when DEBUG is set to True. If you don't have django.contrib.staticfiles in INSTALLED_APPS, you can still manually serve static files using the django.views.static.serve() view.
This is not suitable for production use!
For example, if your STATIC_URL is defined as /static/, you can do this by adding the following snippet to your urls.py:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Note

Note: This helper function works only in debug mode and only if the given prefix is local(e.g. /static/) and not a URL(e.g. http://static.example.com/)

Also this helper function only serves the actual STATIC_ROOT folder; it does not perform static files discovery like django.contrib.staticfiles.

Serving files uploaded by a user during development

During development, you can serve user-uploaded media files from MEDIA_ROOT using the django.views.static.serve() view.
This is not suitable for production use!
For example, if your MEDIA_URL is defined as /media/, you can do this by adding the follwing snippet to your urls.py:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

参考文章:

  1. https://docs.djangoproject.com/en/1.11/ref/contrib/staticfiles/
    2.https://docs.djangoproject.com/en/1.11/howto/static-files/

你可能感兴趣的:(【兰山问题】Django中的静态文件)