背景
Djangoのライブラリであるdjango-storagesを使ったGoogle Cloud Stoargeファイルのdelete方法を試行錯誤で解決したので、upload方法もふくめてそのメモをまとめておきます。
方法
django-storagesのページに基本的な設定方法が書かれています。
DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
GS_BUCKET_NAME = 'YOUR_BUCKET_NAME_GOES_HERE'
と、
from google.oauth2 import service_account
GS_CREDENTIALS = service_account.Credentials.from_service_account_file(
"path/to/credentials.json"
)
の2点を記述して通常通りモデルを定義しておけばuploadまでは動作します。
以下は画像ファイルのモデル例です。
class Image(models.Model):
image = models.ImageField(upload_to='image/')
def __str__(self):
return self.image.name
ただ、ここまでだと、レコードを削除してもGoogle Cloud Storageのファイルは消してくれません。これは(二次情報を読んだだけですが)Django自体の設計思想として、Google Cloud Storageを使う場合に限らず、ファイル削除は自分で実装することとしているようです。
その実装にはレコード削除時に呼ばれる関数をデコレータを使って定義する必要があります。
Google cloud consoleでファイル削除すると(本処理時にGoogle Cloud Storage側にファイルが無い場合)エラーが発生するので例外処理を入れています。
from django.dispatch import receiver
from google.cloud import exceptions
@receiver(models.signals.post_delete, sender=Image)
def auto_delete_image(sender, instance, **kargs):
file = instance.image
try:
file.storage.delete(name=file.name)
except exceptions.NotFound as e:
print(e)
環境変数GOOGLE_APPLICATION_CREDENTIALS
を設定していればgoogle.cloudのモジュールで以下のようにも実装できます。
ただ、この場合google cloudの権限として、storage.buckets.get
を割り当てておかないとエラーになりました。
from google.cloud import storage
from django.conf import settings
@receiver(models.signals.post_delete, sender=Image)
def auto_delete_image(sender, instance, **kargs):
storage_client = storage.Client()
bucket = storage_client.get_bucket(settings.GS_BUCKET_NAME)
blob = bucket.blob(instance.image.name)
try:
blob.delete()
except exceptions.NotFound as e:
print(e)
#補足
Google Cloud Storage側の設定を補足しておきます。しっかり検証していないのですべては不要かもしれませんが私の環境では以下の権限を割り当てたサービスアカウントを発行してます。
- storage.objects.create
- storage.objects.delete
- storage.objects.get
- storage.objects.list
- storage.objects.update
実際の設定方法は公式のリンクを載せておきます。