配置 Django 和 Google 云存储?
Configure Django and Google Cloud Storage?
我不使用Appengine。
我在 VM 上有一个普通的 Django 应用程序 运行。我想使用 Google 云存储来提供我的静态文件,以及 uploading/serving 我的媒体文件。
我有一个水桶。
如何 link 我的 Django 应用程序到我的存储桶?我试过了 django-storages
。这可能行得通,但是我需要做什么来准备我的桶以供我的 Django 应用程序使用?在我的 Django 设置中我需要什么基线配置?
当前设置:
# Google Cloud Storage
# http://django-storages.readthedocs.org/en/latest/backends/apache_libcloud.html
LIBCLOUD_PROVIDERS = {
'google': {
'type' : 'libcloud.storage.types.Provider.GOOGLE_STORAGE',
'user' : <I have no idea>,
'key' : <ditto above>,
'bucket': <my bucket name>,
}
}
DEFAULT_LIBCLOUD_PROVIDER = 'google'
DEFAULT_FILE_STORAGE = 'storages.backends.apache_libcloud.LibCloudStorage'
STATICFILES_STORAGE = 'storages.backends.apache_libcloud.LibCloudStorage'
所以,这基本上 将 工作。 (使用此库和设置)。
让它工作的诀窍是知道从哪里获取 libcloud 的 'user'
和 'key'
参数。
在 Google Cloud Console > Storage
上,单击 Settings
。然后单击名为 Interoperability
的右侧选项卡。在那个面板上,有一个单独的按钮,上面写着类似 Enable Interoperability
的内容。点击它。
瞧! 你现在有了用户名和密钥。
注意: 不要 使用来自 pypi 的 django-storages
。它尚未更新,并且不适用于最新版本的 Django。
使用这个版本:
pip install -e 'git+https://github.com/jschneier/django-storages.git#egg=django-storages'
编辑:如果你想使用反向代理,那么你可以考虑我稍微修改过的版本。
https://github.com/jschneier/django-storages/compare/master...halfnibble:master
描述:
在某些情况下,可能需要使用反向代理加载文件。这可用于减少跨源请求错误。
这个小 PR 允许开发者在 settings.py 中设置一个可选的 LIBCLOUD_PROXY_URL。
用法示例
# Apache VirtualHost conf
ProxyPass /foo http://storage.googleapis.com
ProxyPassReverse /foo http://storage.googleapis.com
# settings.py
LIBCLOUD_PROXY_URL = '/foo/'
Django-storages 有一个用于 Google Cloud Storage 的后端,但没有记录,我在 repo 中发现了这一点。得到它与这个设置一起工作:
DEFAULT_FILE_STORAGE = 'storages.backends.gs.GSBotoStorage'
GS_ACCESS_KEY_ID = 'YourID'
GS_SECRET_ACCESS_KEY = 'YourKEY'
GS_BUCKET_NAME = 'YourBucket'
STATICFILES_STORAGE = 'storages.backends.gs.GSBotoStorage'
要获取 YourKEY 和 YourID,您应该在设置选项卡中创建 Interoperability
密钥。
希望它对您有所帮助,您不必费力地学习它:)
啊,万一你还没有,依赖项是:
pip install django-storages
pip install boto
由于我无法对 Alan Wagner 的回答发表评论,这里补充一下。
如果您正在使用 python3,您可能会遇到此错误,
...
ImportError: No module named 'google_compute_engine'
如果是这样,您将需要安装 google-compute-engine。 /etc/boto.cfg
文件告诉 python 使用 2.7 版本的库。您必须 运行 下一行才能重新生成 /etc/boto.cfg
.
python3 -c "from google_compute_engine.boto.boto_config import BotoConfig; BotoConfig()"
您可能遇到的另一个错误,
...
File "/app/venv/lib/python3.4/site-packages/boto/gs/connection.py", line 95, in create_bucket
data=get_utf8_value(data))
File "/app/venv/lib/python3.4/site-packages/boto/s3/connection.py", line 656, in make_request
auth_path = self.calling_format.build_auth_path(bucket, key)
File "/app/venv/lib/python3.4/site-packages/boto/s3/connection.py", line 94, in build_auth_path
path = '/' + bucket
TypeError: Can't convert 'bytes' object to str implicitly
如果你愿意,我做了一个 pull request to fix this. You may use my repo 作为 pip 依赖项,直到它被合并。
我会尽量使这个 repo 保持最新。我已将默认 develop
分支设置为受保护。我是唯一可以 commit/approve 合并请求的人。我也只提交了一次。
您必须先安装 google-compute-engine 和 运行 上面那一行,然后才能 instalkl/build 我的 boto 存储库。
Django-storages 实际上是一个可行的替代方案。你必须小心它的 Google 云后端
因为它提供的 url()
方法会导致对 Google 的不必要的 HTTP 调用。 (例如,Django 在呈现静态文件时调用 .url())。
https://github.com/jschneier/django-storages/issues/491
settings.py
DEFAULT_FILE_STORAGE = 'config.storage_backends.GoogleCloudMediaStorage'
STATICFILES_STORAGE = 'config.storage_backends.GoogleCloudStaticStorage'
GS_PROJECT_ID = '<google-cloud-project-id>'
GS_MEDIA_BUCKET_NAME = '<name-of-static-bucket>'
GS_STATIC_BUCKET_NAME = '<name-of-static-bucket>'
STATIC_URL = 'https://storage.googleapis.com/{}/'.format(GS_STATIC_BUCKET_NAME)
MEDIA_URL = 'https://storage.googleapis.com/{}/'.format(GS_MEDIA_BUCKET_NAME)
storage_backends.py
"""
GoogleCloudStorage extensions suitable for handing Django's
Static and Media files.
Requires following settings:
MEDIA_URL, GS_MEDIA_BUCKET_NAME
STATIC_URL, GS_STATIC_BUCKET_NAME
In addition to
https://django-storages.readthedocs.io/en/latest/backends/gcloud.html
"""
from django.conf import settings
from storages.backends.gcloud import GoogleCloudStorage
from storages.utils import setting
from urllib.parse import urljoin
class GoogleCloudMediaStorage(GoogleCloudStorage):
"""GoogleCloudStorage suitable for Django's Media files."""
def __init__(self, *args, **kwargs):
if not settings.MEDIA_URL:
raise Exception('MEDIA_URL has not been configured')
kwargs['bucket_name'] = setting('GS_MEDIA_BUCKET_NAME', strict=True)
super(GoogleCloudMediaStorage, self).__init__(*args, **kwargs)
def url(self, name):
""".url that doesn't call Google."""
return urljoin(settings.MEDIA_URL, name)
class GoogleCloudStaticStorage(GoogleCloudStorage):
"""GoogleCloudStorage suitable for Django's Static files"""
def __init__(self, *args, **kwargs):
if not settings.STATIC_URL:
raise Exception('STATIC_URL has not been configured')
kwargs['bucket_name'] = setting('GS_STATIC_BUCKET_NAME', strict=True)
super(GoogleCloudStaticStorage, self).__init__(*args, **kwargs)
def url(self, name):
""".url that doesn't call Google."""
return urljoin(settings.STATIC_URL, name)
注意:默认情况下通过 GOOGLE_APPLICATION_CREDENTIALS 环境变量处理身份验证。
https://cloud.google.com/docs/authentication/production#setting_the_environment_variable
作为最新版本,访问密钥和密钥ID更改为服务帐户文件。我们想像本地服务器一样使用包含 2 个文件夹 static
和 media
的存储桶。低于更新配置:
创建一个类似 gcloud_storages.py
的文件:
"""
Modify django-storages for GCloud to set static, media folder in a bucket
"""
from django.conf import settings
from storages.backends.gcloud import GoogleCloudStorage
class GoogleCloudMediaStorage(GoogleCloudStorage):
"""
GoogleCloudStorage suitable for Django's Media files.
"""
def __init__(self, *args, **kwargs):
kwargs['location'] = 'media'
super(GoogleCloudMediaStorage, self).__init__(*args, **kwargs)
class GoogleCloudStaticStorage(GoogleCloudStorage):
"""
GoogleCloudStorage suitable for Django's Static files
"""
def __init__(self, *args, **kwargs):
kwargs['location'] = 'static'
super(GoogleCloudStaticStorage, self).__init__(*args, **kwargs)
使用 location
参数设置存储桶中静态媒体文件的位置。
在settings.py
from google.oauth2 import service_account
...
GOOGLE_APPLICATION_CREDENTIALS = '/path/service-account.json'
DEFAULT_FILE_STORAGE = 'app.gcloud_storages.GoogleCloudMediaStorage'
STATICFILES_STORAGE = 'app.gcloud_storages.GoogleCloudStaticStorage'
GS_BUCKET_NAME = 'name-of-bucket'
GS_PROJECT_ID = 'project-id'
GS_DEFAULT_ACL = 'publicRead'
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
GOOGLE_APPLICATION_CREDENTIALS
)
我在另一个线程上详细介绍了我的分步过程
- Serve Static files from Google Cloud Storage Bucket (for Django App hosted on GCE)
以下是我的主要参考资料:
- https://django-storages.readthedocs.io/en/latest/backends/gcloud.html
- https://medium.com/@umeshsaruk/upload-to-google-cloud-storage-using-django-storages-72ddec2f0d05
我使用了以下软件包:
pip3 install django-storages # https://pypi.org/project/django-storages/
pip3 install google-cloud-storage # https://pypi.org/project/google-cloud-storage/
2022 年 5 月更新:
按照此说明,您可以将 Django 应用程序连接到 GCS(Google 云存储) 上的存储桶,您可以提供静态文件并提供、上传并删除您的媒体文件。
例如,您在 GCS:
上有 存储桶“my-django-bucket”
并且您有服务帐户“my-django-bucket-sa”然后您需要复制(Ctrl+C)电子邮件“my-django-bucket-sa@myproject-347313.iam.gserviceaccount.com":
接下来,在存储桶“my-django-bucket”的存储桶详细信息中,点击“权限” " 然后 "ADD":
然后,启用服务帐户“my-django-bucket-sa” 完全控制 GCS 资源,粘贴(Ctrl+V) 电子邮件“my-django-bucket-sa@myproject-347313.iam.gserviceaccount.com”到“新校长”然后选择角色“Storage Admin”,然后单击“SAVE”。 *如果您不想要 可以完全控制 GCS 资源的角色“Storage Admin”,请勾选 IAM roles for Cloud Storage 选择其他角色:
接下来,要使所有用户都能查看(阅读)文件,请键入 “allUsers” 到 “新主体”,然后选择 角色“存储遗留对象Reader” 然后点击“保存”:
然后,您应该会被询问,如下所示,因此请单击 “允许 PUBLIC 访问”:
最后,您可以将角色“Storage Admin”添加到服务帐户“my-django-bucket-sa”,并且角色“存储遗留对象 Reader” 到 “allUsers”:
接下来,您需要下载JSON中服务帐号“my-django-bucket-sa”的私钥,所以点击"Manage keys" from 3个点“⋮”:
然后,点击 “创建新密钥” 来自 “添加密钥”:
然后,选择 "JSON" 然后点击 "创建"
最后,您可以在JSON“myproject-347313-020754294843.json”[=]中下载服务帐号“my-django-bucket-sa”的私钥。 421=]:
现在,您有一个 django 项目,并且有 一个设置文件夹“core”,其中有 “static/core/core.js” 和 "settings.py" 和 一个应用程序文件夹“myapp” 其中有 “static/myapp/myapp .css"如下图:
接下来,你需要将 "myproject-347313-020754294843.json" 放入 django 项目根目录,其中 "db.sqlite3"和“manage.py”是:
那么,你最好将 "myproject-347313-020754294843.json" 重命名为更短且合理的名称,例如 "gcpCredentials.json ":
接下来,您需要安装 "django-storages[google]" 以与 "[=590] 连接并通信=] GCS(Google 云存储):
pip install django-storages[google]
通过安装"django-storages[google]",可以得到"django-storages"和其他必要的包如下图:
"requirements.txt"
django-storages==1.12.3
cachetools==4.2.4
google-api-core==2.7.2
google-auth==2.6.5
google-cloud-core==2.3.0
google-cloud-storage==2.0.0
google-crc32c==1.3.0
google-resumable-media==2.3.2
googleapis-common-protos==1.56.0
protobuf==3.19.4
pyasn1==0.4.8
pyasn1-modules==0.2.8
小心,如果你安装 "django-storages" 而没有 "[google]" 如图所示以下:
pip install django-storages
只能得到"django-storages"如下图
"requirements.txt"
django-storages==1.12.3
接下来,在 “核心”文件夹 中创建 "gcsUtils.py",其中 "settings.py" 是:
然后,将此代码放在 "gcsUtils.py" 下方以定义 "Static" 和 "Media" 变量 其中每个都有 a "GoogleCloudStorage" class object:
# "core/gcsUtils.py"
from storages.backends.gcloud import GoogleCloudStorage
Static = lambda: GoogleCloudStorage(location='static')
Media = lambda: GoogleCloudStorage(location='media')
接下来,将下面的代码添加到 "settings.py"。 *"STATICFILES_STORAGE" 就像 "STATIC_ROOT" 和 "[=656] 的组合=]" 和 "DEFAULT_FILE_STORAGE" 就像 "MEDIA_ROOT" 和 "MEDIA_URL":
# "core/settings.py"
from google.oauth2 import service_account
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
然后,运行下面这个命令:
python manage.py collectstatic
现在,“静态”文件夹 已在 "my-django-bucket":
中创建
还有atic 文件从“admin”和“application”文件夹收集到“static”文件夹 my-django-bucket ":
这是 "myapp.css",位于 "myapp" 文件夹:
但如您所见,静态文件并未从设置文件夹“core”收集到“static”文件夹 [= =267=]"my-django-bucket":
因为"STATICFILES_STORAGE"只能从"admin"和"application"文件夹收集静态文件,不能从其他文件夹,例如 设置文件夹“core”:
# "core/settings.py"
STATICFILES_STORAGE = 'core.gcsUtils.Static'
因此,要从设置文件夹“core”收集静态文件到中的“static”文件夹” my-django-bucket":
需要在"settings.py"中添加"STATICFILES_DIRS"如下图:
# "core/settings.py"
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
那么,这是“settings.py”的完整代码:
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
然后,运行下面的命令:
python manage.py collectstatic
然后,静态文件从设置文件夹“core”收集到“static”文件夹 in ” my-django-bucket":
这是 "core.js" “核心”文件夹:
接下来,这是 "myapp/models.py":
的代码
# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField(upload_to='images/fruits')
def __str__(self):
return str(self.image)
这是 "myapp/admin.py":
的代码
# "myapp/admin.py"
from django.contrib import admin
from .models import Image
admin.site.register(Image)
然后,上传"orange.jpg":
现在,“媒体”文件夹 已在 "my-django-bucket":
中创建
和"orange.jpg"上传在"media/images/fruits":
又因为"GS_FILE_OVERWRITE = False"设置在"settings.py":
# "core/settings.py"
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
如果再次上传同名文件“orange.jpg”:
然后,将唯一ID“_VPJxGBW”添加到“orange.jpg”以防止文件覆盖然后,"orange_VPJxGBW.jpg"上传如下图:
接下来如果orange.jpgmedia/images/fruits:
然后,更新(更改)"orange.jpg" 到 "apple.jpg" 正在上传:
然后,"apple.jpg" 上传到 "media/images/fruits" 但是 "orange.jpg"还在"media/images/fruits"没有删除:
而如果"orange.jpg"在"media/images/fruits":
然后,删除"orange.jpg":
但是"orange.jpg"还在"media/images/fruits"没有删:
因此,要在更新(更改)和删除时删除上传的文件,您需要安装"django-cleanup":
pip install django-cleanup
然后,在"settings.py""INSTALLED_APPS"的底部添加:
# "core/settings.py"
INSTALLED_APPS = (
...,
'django_cleanup.apps.CleanupConfig', # Here
)
那么,如果media/images/fruitsorange.jpg:
然后,更新(更改)"orange.jpg" 到 "apple.jpg" 正在上传:
然后,"apple.jpg"上传到"media/images/fruits"和 "orange.jpg" 从 " 中删除"=579=]":
而如果"orange.jpg"在"media/images/fruits":
然后,删除"orange.jpg":
然后,"orange.jpg"从"media/images/fruits":
中删除
最后,您刚刚在 "settings.py" 中设置的 GCS Bucket Settings "DEBUG = True" 和 "DEBUG = False":
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
而且,还会有"STATIC_ROOT"、"STATIC_URL"、"MEDIA_ROOT", "MEDIA_URL" 与 GCS 桶设置 在 "settings.py" 如下图。所以,在这种情况下,"STATIC_ROOT","STATIC_URL"、"MEDIA_ROOT" 和 "MEDIA_URL" 不工作,而 GCS 桶设置 与 "my-django-bucket" 在 GCS:
# "core/settings.py"
from google.oauth2 import service_account
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
'''GCS Bucket Settings Start'''
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
'''GCS Bucket Settings End'''
所以,如果你想 "STATIC_ROOT", "STATIC_URL", "MEDIA_ROOT" 和 "MEDIA_URL" 工作,只需评论 GCS Bucket Settings然后设置"STATICFILES_DIRS"如下图:
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
"""
'''GCS Bucket Settings Start'''
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
'''GCS Bucket Settings End'''
"""
我不使用Appengine。
我在 VM 上有一个普通的 Django 应用程序 运行。我想使用 Google 云存储来提供我的静态文件,以及 uploading/serving 我的媒体文件。
我有一个水桶。
如何 link 我的 Django 应用程序到我的存储桶?我试过了 django-storages
。这可能行得通,但是我需要做什么来准备我的桶以供我的 Django 应用程序使用?在我的 Django 设置中我需要什么基线配置?
当前设置:
# Google Cloud Storage
# http://django-storages.readthedocs.org/en/latest/backends/apache_libcloud.html
LIBCLOUD_PROVIDERS = {
'google': {
'type' : 'libcloud.storage.types.Provider.GOOGLE_STORAGE',
'user' : <I have no idea>,
'key' : <ditto above>,
'bucket': <my bucket name>,
}
}
DEFAULT_LIBCLOUD_PROVIDER = 'google'
DEFAULT_FILE_STORAGE = 'storages.backends.apache_libcloud.LibCloudStorage'
STATICFILES_STORAGE = 'storages.backends.apache_libcloud.LibCloudStorage'
所以,这基本上 将 工作。 (使用此库和设置)。
让它工作的诀窍是知道从哪里获取 libcloud 的 'user'
和 'key'
参数。
在 Google Cloud Console > Storage
上,单击 Settings
。然后单击名为 Interoperability
的右侧选项卡。在那个面板上,有一个单独的按钮,上面写着类似 Enable Interoperability
的内容。点击它。
瞧! 你现在有了用户名和密钥。
注意: 不要 使用来自 pypi 的 django-storages
。它尚未更新,并且不适用于最新版本的 Django。
使用这个版本:
pip install -e 'git+https://github.com/jschneier/django-storages.git#egg=django-storages'
编辑:如果你想使用反向代理,那么你可以考虑我稍微修改过的版本。 https://github.com/jschneier/django-storages/compare/master...halfnibble:master
描述: 在某些情况下,可能需要使用反向代理加载文件。这可用于减少跨源请求错误。
这个小 PR 允许开发者在 settings.py 中设置一个可选的 LIBCLOUD_PROXY_URL。
用法示例
# Apache VirtualHost conf
ProxyPass /foo http://storage.googleapis.com
ProxyPassReverse /foo http://storage.googleapis.com
# settings.py
LIBCLOUD_PROXY_URL = '/foo/'
Django-storages 有一个用于 Google Cloud Storage 的后端,但没有记录,我在 repo 中发现了这一点。得到它与这个设置一起工作:
DEFAULT_FILE_STORAGE = 'storages.backends.gs.GSBotoStorage'
GS_ACCESS_KEY_ID = 'YourID'
GS_SECRET_ACCESS_KEY = 'YourKEY'
GS_BUCKET_NAME = 'YourBucket'
STATICFILES_STORAGE = 'storages.backends.gs.GSBotoStorage'
要获取 YourKEY 和 YourID,您应该在设置选项卡中创建 Interoperability
密钥。
希望它对您有所帮助,您不必费力地学习它:)
啊,万一你还没有,依赖项是:
pip install django-storages
pip install boto
由于我无法对 Alan Wagner 的回答发表评论,这里补充一下。
如果您正在使用 python3,您可能会遇到此错误,
...
ImportError: No module named 'google_compute_engine'
如果是这样,您将需要安装 google-compute-engine。 /etc/boto.cfg
文件告诉 python 使用 2.7 版本的库。您必须 运行 下一行才能重新生成 /etc/boto.cfg
.
python3 -c "from google_compute_engine.boto.boto_config import BotoConfig; BotoConfig()"
您可能遇到的另一个错误,
...
File "/app/venv/lib/python3.4/site-packages/boto/gs/connection.py", line 95, in create_bucket
data=get_utf8_value(data))
File "/app/venv/lib/python3.4/site-packages/boto/s3/connection.py", line 656, in make_request
auth_path = self.calling_format.build_auth_path(bucket, key)
File "/app/venv/lib/python3.4/site-packages/boto/s3/connection.py", line 94, in build_auth_path
path = '/' + bucket
TypeError: Can't convert 'bytes' object to str implicitly
如果你愿意,我做了一个 pull request to fix this. You may use my repo 作为 pip 依赖项,直到它被合并。
我会尽量使这个 repo 保持最新。我已将默认 develop
分支设置为受保护。我是唯一可以 commit/approve 合并请求的人。我也只提交了一次。
您必须先安装 google-compute-engine 和 运行 上面那一行,然后才能 instalkl/build 我的 boto 存储库。
Django-storages 实际上是一个可行的替代方案。你必须小心它的 Google 云后端
因为它提供的 url()
方法会导致对 Google 的不必要的 HTTP 调用。 (例如,Django 在呈现静态文件时调用 .url())。
https://github.com/jschneier/django-storages/issues/491
settings.py
DEFAULT_FILE_STORAGE = 'config.storage_backends.GoogleCloudMediaStorage'
STATICFILES_STORAGE = 'config.storage_backends.GoogleCloudStaticStorage'
GS_PROJECT_ID = '<google-cloud-project-id>'
GS_MEDIA_BUCKET_NAME = '<name-of-static-bucket>'
GS_STATIC_BUCKET_NAME = '<name-of-static-bucket>'
STATIC_URL = 'https://storage.googleapis.com/{}/'.format(GS_STATIC_BUCKET_NAME)
MEDIA_URL = 'https://storage.googleapis.com/{}/'.format(GS_MEDIA_BUCKET_NAME)
storage_backends.py
"""
GoogleCloudStorage extensions suitable for handing Django's
Static and Media files.
Requires following settings:
MEDIA_URL, GS_MEDIA_BUCKET_NAME
STATIC_URL, GS_STATIC_BUCKET_NAME
In addition to
https://django-storages.readthedocs.io/en/latest/backends/gcloud.html
"""
from django.conf import settings
from storages.backends.gcloud import GoogleCloudStorage
from storages.utils import setting
from urllib.parse import urljoin
class GoogleCloudMediaStorage(GoogleCloudStorage):
"""GoogleCloudStorage suitable for Django's Media files."""
def __init__(self, *args, **kwargs):
if not settings.MEDIA_URL:
raise Exception('MEDIA_URL has not been configured')
kwargs['bucket_name'] = setting('GS_MEDIA_BUCKET_NAME', strict=True)
super(GoogleCloudMediaStorage, self).__init__(*args, **kwargs)
def url(self, name):
""".url that doesn't call Google."""
return urljoin(settings.MEDIA_URL, name)
class GoogleCloudStaticStorage(GoogleCloudStorage):
"""GoogleCloudStorage suitable for Django's Static files"""
def __init__(self, *args, **kwargs):
if not settings.STATIC_URL:
raise Exception('STATIC_URL has not been configured')
kwargs['bucket_name'] = setting('GS_STATIC_BUCKET_NAME', strict=True)
super(GoogleCloudStaticStorage, self).__init__(*args, **kwargs)
def url(self, name):
""".url that doesn't call Google."""
return urljoin(settings.STATIC_URL, name)
注意:默认情况下通过 GOOGLE_APPLICATION_CREDENTIALS 环境变量处理身份验证。
https://cloud.google.com/docs/authentication/production#setting_the_environment_variable
作为最新版本,访问密钥和密钥ID更改为服务帐户文件。我们想像本地服务器一样使用包含 2 个文件夹 static
和 media
的存储桶。低于更新配置:
创建一个类似 gcloud_storages.py
的文件:
"""
Modify django-storages for GCloud to set static, media folder in a bucket
"""
from django.conf import settings
from storages.backends.gcloud import GoogleCloudStorage
class GoogleCloudMediaStorage(GoogleCloudStorage):
"""
GoogleCloudStorage suitable for Django's Media files.
"""
def __init__(self, *args, **kwargs):
kwargs['location'] = 'media'
super(GoogleCloudMediaStorage, self).__init__(*args, **kwargs)
class GoogleCloudStaticStorage(GoogleCloudStorage):
"""
GoogleCloudStorage suitable for Django's Static files
"""
def __init__(self, *args, **kwargs):
kwargs['location'] = 'static'
super(GoogleCloudStaticStorage, self).__init__(*args, **kwargs)
使用 location
参数设置存储桶中静态媒体文件的位置。
在settings.py
from google.oauth2 import service_account
...
GOOGLE_APPLICATION_CREDENTIALS = '/path/service-account.json'
DEFAULT_FILE_STORAGE = 'app.gcloud_storages.GoogleCloudMediaStorage'
STATICFILES_STORAGE = 'app.gcloud_storages.GoogleCloudStaticStorage'
GS_BUCKET_NAME = 'name-of-bucket'
GS_PROJECT_ID = 'project-id'
GS_DEFAULT_ACL = 'publicRead'
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
GOOGLE_APPLICATION_CREDENTIALS
)
我在另一个线程上详细介绍了我的分步过程
- Serve Static files from Google Cloud Storage Bucket (for Django App hosted on GCE)
以下是我的主要参考资料:
- https://django-storages.readthedocs.io/en/latest/backends/gcloud.html
- https://medium.com/@umeshsaruk/upload-to-google-cloud-storage-using-django-storages-72ddec2f0d05
我使用了以下软件包:
pip3 install django-storages # https://pypi.org/project/django-storages/
pip3 install google-cloud-storage # https://pypi.org/project/google-cloud-storage/
2022 年 5 月更新:
按照此说明,您可以将 Django 应用程序连接到 GCS(Google 云存储) 上的存储桶,您可以提供静态文件并提供、上传并删除您的媒体文件。
例如,您在 GCS:
上有 存储桶“my-django-bucket”并且您有服务帐户“my-django-bucket-sa”然后您需要复制(Ctrl+C)电子邮件“my-django-bucket-sa@myproject-347313.iam.gserviceaccount.com":
接下来,在存储桶“my-django-bucket”的存储桶详细信息中,点击“权限” " 然后 "ADD":
然后,启用服务帐户“my-django-bucket-sa” 完全控制 GCS 资源,粘贴(Ctrl+V) 电子邮件“my-django-bucket-sa@myproject-347313.iam.gserviceaccount.com”到“新校长”然后选择角色“Storage Admin”,然后单击“SAVE”。 *如果您不想要 可以完全控制 GCS 资源的角色“Storage Admin”,请勾选 IAM roles for Cloud Storage 选择其他角色:
接下来,要使所有用户都能查看(阅读)文件,请键入 “allUsers” 到 “新主体”,然后选择 角色“存储遗留对象Reader” 然后点击“保存”:
然后,您应该会被询问,如下所示,因此请单击 “允许 PUBLIC 访问”:
最后,您可以将角色“Storage Admin”添加到服务帐户“my-django-bucket-sa”,并且角色“存储遗留对象 Reader” 到 “allUsers”:
接下来,您需要下载JSON中服务帐号“my-django-bucket-sa”的私钥,所以点击"Manage keys" from 3个点“⋮”:
然后,点击 “创建新密钥” 来自 “添加密钥”:
然后,选择 "JSON" 然后点击 "创建"
最后,您可以在JSON“myproject-347313-020754294843.json”[=]中下载服务帐号“my-django-bucket-sa”的私钥。 421=]:
现在,您有一个 django 项目,并且有 一个设置文件夹“core”,其中有 “static/core/core.js” 和 "settings.py" 和 一个应用程序文件夹“myapp” 其中有 “static/myapp/myapp .css"如下图:
接下来,你需要将 "myproject-347313-020754294843.json" 放入 django 项目根目录,其中 "db.sqlite3"和“manage.py”是:
那么,你最好将 "myproject-347313-020754294843.json" 重命名为更短且合理的名称,例如 "gcpCredentials.json ":
接下来,您需要安装 "django-storages[google]" 以与 "[=590] 连接并通信=] GCS(Google 云存储):
pip install django-storages[google]
通过安装"django-storages[google]",可以得到"django-storages"和其他必要的包如下图:
"requirements.txt"
django-storages==1.12.3
cachetools==4.2.4
google-api-core==2.7.2
google-auth==2.6.5
google-cloud-core==2.3.0
google-cloud-storage==2.0.0
google-crc32c==1.3.0
google-resumable-media==2.3.2
googleapis-common-protos==1.56.0
protobuf==3.19.4
pyasn1==0.4.8
pyasn1-modules==0.2.8
小心,如果你安装 "django-storages" 而没有 "[google]" 如图所示以下:
pip install django-storages
只能得到"django-storages"如下图
"requirements.txt"
django-storages==1.12.3
接下来,在 “核心”文件夹 中创建 "gcsUtils.py",其中 "settings.py" 是:
然后,将此代码放在 "gcsUtils.py" 下方以定义 "Static" 和 "Media" 变量 其中每个都有 a "GoogleCloudStorage" class object:
# "core/gcsUtils.py"
from storages.backends.gcloud import GoogleCloudStorage
Static = lambda: GoogleCloudStorage(location='static')
Media = lambda: GoogleCloudStorage(location='media')
接下来,将下面的代码添加到 "settings.py"。 *"STATICFILES_STORAGE" 就像 "STATIC_ROOT" 和 "[=656] 的组合=]" 和 "DEFAULT_FILE_STORAGE" 就像 "MEDIA_ROOT" 和 "MEDIA_URL":
# "core/settings.py"
from google.oauth2 import service_account
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
然后,运行下面这个命令:
python manage.py collectstatic
现在,“静态”文件夹 已在 "my-django-bucket":
中创建还有atic 文件从“admin”和“application”文件夹收集到“static”文件夹 my-django-bucket ":
这是 "myapp.css",位于 "myapp" 文件夹:
但如您所见,静态文件并未从设置文件夹“core”收集到“static”文件夹 [= =267=]"my-django-bucket":
因为"STATICFILES_STORAGE"只能从"admin"和"application"文件夹收集静态文件,不能从其他文件夹,例如 设置文件夹“core”:
# "core/settings.py"
STATICFILES_STORAGE = 'core.gcsUtils.Static'
因此,要从设置文件夹“core”收集静态文件到中的“static”文件夹” my-django-bucket":
需要在"settings.py"中添加"STATICFILES_DIRS"如下图:
# "core/settings.py"
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
那么,这是“settings.py”的完整代码:
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
然后,运行下面的命令:
python manage.py collectstatic
然后,静态文件从设置文件夹“core”收集到“static”文件夹 in ” my-django-bucket":
这是 "core.js" “核心”文件夹:
接下来,这是 "myapp/models.py":
的代码# "myapp/models.py"
from django.db import models
class Image(models.Model):
image = models.ImageField(upload_to='images/fruits')
def __str__(self):
return str(self.image)
这是 "myapp/admin.py":
的代码# "myapp/admin.py"
from django.contrib import admin
from .models import Image
admin.site.register(Image)
然后,上传"orange.jpg":
现在,“媒体”文件夹 已在 "my-django-bucket":
中创建和"orange.jpg"上传在"media/images/fruits":
又因为"GS_FILE_OVERWRITE = False"设置在"settings.py":
# "core/settings.py"
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
如果再次上传同名文件“orange.jpg”:
然后,将唯一ID“_VPJxGBW”添加到“orange.jpg”以防止文件覆盖然后,"orange_VPJxGBW.jpg"上传如下图:
接下来如果orange.jpgmedia/images/fruits:
然后,更新(更改)"orange.jpg" 到 "apple.jpg" 正在上传:
然后,"apple.jpg" 上传到 "media/images/fruits" 但是 "orange.jpg"还在"media/images/fruits"没有删除:
而如果"orange.jpg"在"media/images/fruits":
然后,删除"orange.jpg":
但是"orange.jpg"还在"media/images/fruits"没有删:
因此,要在更新(更改)和删除时删除上传的文件,您需要安装"django-cleanup":
pip install django-cleanup
然后,在"settings.py""INSTALLED_APPS"的底部添加:
# "core/settings.py"
INSTALLED_APPS = (
...,
'django_cleanup.apps.CleanupConfig', # Here
)
那么,如果media/images/fruitsorange.jpg:
然后,更新(更改)"orange.jpg" 到 "apple.jpg" 正在上传:
然后,"apple.jpg"上传到"media/images/fruits"和 "orange.jpg" 从 " 中删除"=579=]":
而如果"orange.jpg"在"media/images/fruits":
然后,删除"orange.jpg":
然后,"orange.jpg"从"media/images/fruits":
中删除最后,您刚刚在 "settings.py" 中设置的 GCS Bucket Settings "DEBUG = True" 和 "DEBUG = False":
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
而且,还会有"STATIC_ROOT"、"STATIC_URL"、"MEDIA_ROOT", "MEDIA_URL" 与 GCS 桶设置 在 "settings.py" 如下图。所以,在这种情况下,"STATIC_ROOT","STATIC_URL"、"MEDIA_ROOT" 和 "MEDIA_URL" 不工作,而 GCS 桶设置 与 "my-django-bucket" 在 GCS:
# "core/settings.py"
from google.oauth2 import service_account
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
'''GCS Bucket Settings Start'''
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
'''GCS Bucket Settings End'''
所以,如果你想 "STATIC_ROOT", "STATIC_URL", "MEDIA_ROOT" 和 "MEDIA_URL" 工作,只需评论 GCS Bucket Settings然后设置"STATICFILES_DIRS"如下图:
# "core/settings.py"
from google.oauth2 import service_account
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
"""
'''GCS Bucket Settings Start'''
# Collect static files from the settings folder
# "core" which is not "admin" and "application" folder
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'core/static'),
]
# Set "static" folder
STATICFILES_STORAGE = 'core.gcsUtils.Static'
# Set "media" folder
DEFAULT_FILE_STORAGE = 'core.gcsUtils.Media'
GS_BUCKET_NAME = 'my-django-bucket'
# Add an unique ID to a file name if same file name exists
GS_FILE_OVERWRITE = False
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
os.path.join(BASE_DIR, 'gcpCredentials.json'),
)
'''GCS Bucket Settings End'''
"""