如何在Django生产环境中提供媒体文件服务?

21

在我的settings.py文件中:

DEBUG = False
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

STATIC_URL = '/static/'
LOGIN_URL = '/login/'
MEDIA_URL = '/media/'

在我的urls.py文件中:

urlpatterns += static(settings.STATIC_URL, document_root = settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
当我上传个人资料图片时,它会上传到指定的文件夹。但当我访问用户资料 URL 时,终端会显示以下错误。
"GET /media/profile_images/a_34.jpg HTTP/1.1" 404 103

a_34.png存在于/media/profile_images/中。

那么为什么它在浏览器上没有显示,而我收到404错误?


因为Django的开发人员坚持认为,在生产环境中,您应该配置您的Web服务器指向那个静态媒体根目录。 - Antti Haapala -- Слава Україні
@AnttiHaapala 现在我该怎么办? - H.G.
8个回答

14

Django不适用于在生产环境中提供媒体文件。您必须配置STATIC_ROOT设置并别名Web服务器以直接提供服务。

例如

如果您正在生产中使用Apache Web服务器,请将以下内容添加到您的虚拟主机配置中。

Alias /media/ /path/to/media_file/

<Directory /path/to/media_file/>
Order deny,allow
Allow from all
</Directory>

如果您使用Nginx,则需要使用类似以下内容:

location /media {
    alias /path/to/media/file; # Change to your own media directory here.
    access_log off;
}

你也可以使用 django-storages 从AWS S3或其他云服务器提供静态文件。


1
这可能是一个愚蠢的问题,但我如何知道我是否正在使用Apache或Nginx服务器?当我部署Django时,我使用gunicorn。那么我必须停止使用gunicorn吗? - Alex Joslin
在我的情况下,使用root而不是别名(alias)适用于Nginx。 - Uttam Patel

8

Django不建议在生产环境中从服务器上提供媒体文件。使用像Amazon S3这样的云服务来提供您的媒体文件。请参阅此Django文档提供媒体,然后在MEDIA_URL中提供该路径。


3

您可以使用S3 Amazon来存储静态和媒体文件,这将更好。


S3 Amazon存在的问题

将S3存储桶显示为文件系统的一部分具有可怕的性能,并且随机失败。当我们复制大量文件时,需要花费10、15或20分钟才能完成复制,使得在不需要时部署需要很长时间。如果直接发送到S3中,相同的复制命令只需约1分钟即可完成。

解决方案

对S3BotoStorage进行两次子类化,一个用于静态文件,另一个用于媒体文件,这允许我们为每种类型使用不同的存储桶和子目录(参见:custom_storage.py)。

更新设置

1. AWS_STORAGE_BUCKET_NAME  needs to be bucket to hold static files and media files
2. MEDIAFILES_BUCKET
3. MEDIAFILES_LOCATION
4.DEFAULT_FILE_STORAGE
5.STATICFILES_BUCKET
6.STATICFILES_LOCATION
This is the subdirectory under the S3 bucket for the app
7.STATIC_URL
8.STATICFILES_STORAGE

创建 custom_storage.py 文件,并填入以下内容:
from django.utils.deconstruct import deconstructible
from storages.backends.s3boto import S3BotoStorage
from django.conf import settings

@deconstructible
class StaticS3Storage(S3BotoStorage):
   bucket_name = settings.STATICFILES_BUCKET
   location = settings.STATICFILES_LOCATION

@deconstructible
class MediaS3Storage(S3BotoStorage):
   bucket_name = settings.MEDIAFILES_BUCKET
   location = settings.MEDIAFILES_LOCATION

以下是更新 settings.py.tmpl 的示例,根据我的 stack.json 进行设置(如上所述)。

MEDIAFILES_BUCKET = '<%= @node["apps_data"]["aws"]["buckets"]["bucket-name"] %>'
MEDIAFILES_LOCATION = 'folder_name_for_media_files_in_bucket'
DEFAULT_FILE_STORAGE = 'custom_storage.MediaS3Storage'

# If we're not using our S3 backend storage we need to serve the media files via path
   if DEFAULT_FILE_STORAGE == "custom_storage.MediaS3Storage":
       MEDIA_URL = 'https://%s.s3-website-us-east-1.amazonaws.com/%s/' %      (MEDIAFILES_BUCKET, MEDIAFILES_LOCATION)
   else:
       MEDIA_URL = '/media/'

   STATICFILES_BUCKET = '<%= @node["apps_data"]["aws"]["buckets"]["bucket-name"] %>'
   STATICFILES_LOCATION = 'folder_name_for_static_files_in_bucket'
   STATICFILES_STORAGE = '<%= @node["deploy_data"]["project_name"]["django_static_files_storage"] %>'

# If we're not using our S3 backend storage we need to serve the static files via path
   if STATICFILES_STORAGE == "custom_storage.StaticS3Storage":
       STATIC_URL = 'https://%s.s3-website-us-east-1.amazonaws.com/%s/' % (STATICFILES_BUCKET, STATICFILES_LOCATION)
   else:
       STATIC_URL = '/static/'

使用staticfiles Django模板标签加载静态文件

在模板中将所有的{% load static %}替换为{% load static from staticfiles %}

使用“static”从静态文件中可以利用不同的后端文件,包括S3后端或本地文件后端。使用“load static”使用Django模板标签库,该库无法处理不同的后端。

在包含静态文件时,在模板中使用“static from staticfiles”: {% static “path/to/the/file.ext” %} 这将找出文件的完整路径,如果它在S3中,则会插入文件的完整URL。

示例

<link rel="stylesheet" type="text/css" href="{% load static from staticfiles %}{% static "css/style.css" %}”>

有用信息

“django.contrib.staticfiles.storage.StaticFilesStorage” 是Django默认的静态文件后端。

参考资料

https://docs.djangoproject.com/zh-hans/1.9/howto/static-files/ https://www.caktusgroup.com/blog/2014/11/10/Using-Amazon-S3-to-store-your-Django-sites-static-and-media-files/


3

对于nginx,在以下配置行中可以正常工作:

location /media {
    alias /home/ubuntu/speedy-net/media; # Change to your own media directory here.
    access_log off;
}

此外,还可以查看我在Code Review上提出的相关问题


1
您需要在生产环境中设置一个服务器来提供静态内容。当仅 Debug 为 True 时,Django 将提供静态内容。因此,您需要:
1) 设置一个服务器
2) 将服务器的媒体路径指向 STATIC_ROOT 目录
3) 运行 Django 的 collectstatic 命令,将所有静态文件收集到 STATIC_ROOT 中。
请参考。

https://docs.djangoproject.com/en/1.10/howto/static-files/


1
以下方法适用于我:
我在Apache配置文件中添加了以下配置:
alias /media/ /path/to/media/
<Directory /alchemus/django/WebForm/media>
   Require all granted
</Directory>

settings.py 文件包含了以下关于媒体文件的设置:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

请确保在urls.py中设置以下内容:
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

上述设置是为了确保Django服务器仅在开发环境下提供媒体文件,在生产环境中,提供媒体文件应该由Apache服务器处理。
参考文献:https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/modwsgi/#serving-files

1

只需在 urls.py 中添加此代码即可。

urlpatterns = [
       .........

       .........

    
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)


urlpatterns += static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)

1
我遇到了同样的错误,但是逻辑是当Django处于生产模式时,它会提供媒体文件。这意味着当`debug`为`True`时,但当`debug`设置为`False`时,即处于生产模式,您还需要在`urls_pattern`中指定媒体URL。
我用以下方法解决了这个问题:
# import serve and repath
from django.views.static import serve
from django.urls import path, include,re_path

然后添加了:
re_path(r'^media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT}),

to my urls_patterns.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接