使用 django-storages 时如何添加 user-defined S3 元数据

How do you add user-defined S3 metadata in when using django-storages

我在 django-storages 1.12.3 中使用 django 3.1.0。 我正在使用 S3 后端来存储媒体文件 (Minio)。 我正在尝试 post 文件到 S3,并将额外的用户元数据包含到 S3 object。这个额外的元数据来自用于将文件上传到 django 的 POST 请求。使用 S3,可以添加自定义元数据,方法是将额外的 key-value 对添加到 HTTP header 中,以便在上传文件时发送到 S3 服务器的 POST 请求,其中自定义键是前缀为 'X-Amz-Meta-'.

我在 Django 模型中使用 FileField,文件是使用 REST API 端点上传的。 据我了解,当django收到文件时,它会暂时存储它,然后在模型实例上保存FielField时,文件被posted到S3服务器。我想修改流程,以便从请求中获取自定义元数据并将其包含在 post 到 S3 服务器中。

知道如何从初始请求中获取数据,并将其传递给发送到 S3 的 POST 请求的 header 吗?

更新

在尝试了 Helge Schneider 的回答中的选项 1 后,我做了一些修改并让它工作。

我使用的是django rest framework,所以我修改了serializer.save()方法。

from .models import MyModel
from rest_framework import serializers

class MyModelSerialzer(serializers.ModelSerializer):

    class Meta:
        model = SessionFile
        fields = ['file', 'my_other_field']

    def save(self):
        file = self.validated_data['file']
        my_other_field = self.validated_data['my_other_field']
        mymodel = MyModel(file=file, my_other_field=my_other_field)
        options_dict = {"Metadata": {"metadata1": "ImageName", 
                                    "metadata2": "ImagePROPERTIES",
                                    "metadata3": "ImageCREATIONDATE"}
                        } 
        mymodel.file.storage.object_parameters.update(options_dict)
        mymodel.save()

有两种可能的选择:

1.在调用保存方法之前更新存储的参数class

一个选项是在调用保存方法和更新 object_parameters 属性之前从模型的文件字段更新存储 class。

views.py

import MyModel


def my_view(request):
    mymodel = MyModel()
    options_dict = {"Metadata": {"metadata1": "ImageName", 
                                 "metadata2": "ImagePROPERTIES",
                                 "metadata3": "ImageCREATIONDATE"}
                    } 
    mymodel.filefield.storage.object_parameters.update(options_dict)
    mymodel.filefield.save()

2。使用 boto3

手动上传文件

另一种选择是使用 boto3 客户端手动上传文件(Documentation with the upload_fileobj 方法。

然后您可以使用以下摘自 this answer 的代码设置对象元数据:

import boto3
s3 = boto3.resource('s3')
options_dict = {"Metadata": {"metadata1": "ImageName", 
                             "metadata2": "ImagePROPERTIES",
                             "metadata3": "ImageCREATIONDATE"}
s3.upload_fileobj(file, bucketname, key, ExtraArgs=options_dict)

之后,您必须将 FileField 的 name 属性 设置为 S3 Bucket 中的键,如 this answer.

中所述
object.filefield.name = 'file/key/in/bucket'