如何为动态生成的 google 云存储对象获取有效的 blobstore 密钥?

How do I get a valid blobstore key for a google cloudstorage object that is generated dynamically?

我有一个用例,我需要动态生成一个 csv/txt 文件,然后将文件的密钥保存到数据存储区,以便稍后可以下载该文件。我似乎在生成与 Ferris 的下载 uri 结合使用的有效密钥时遇到问题。 例如:

import cloudstorage
from google.appengine.ext import blobstore
@route
def make_file(self):
    # Hardcoded filename, this will overwrite prior file if it exists
    filename = '/mydomain.appspot.com/some_folder/myawesometextfile2.txt'

    # Create file 
    gcs_file = cloudstorage.open(filename,'w',content_type='text/plain')

    # Generate the file's contents (pretend this is being done dynamically)
    gcs_file.write('Doe,John\n')
    gcs_file.write('Smith,Jane\n')

    # Close the file
    gcs_file.close() 

    # This is supposed to create a blobkey that represents the cloud object
    psuedo_blobkey = blobstore.create_gs_key('/gs'+filename)

    # This is supposed to also create a blobkey...I think?
    another_key = blobstore.BlobKey(psuedo_blobkey)

    # Here I attempt to store this in the datastore.
    new_file = self.meta.Model(
                        file_key = another_key,
                        file_name_actual = filename,
                        )
    new_file.put() 

如果我尝试将 "psuedo_blobkey" 保存到我的 NDB 模型中,我会收到类似 "Expected BlobKey, got AMIfv-yadda-yadda-yadda".

的错误

如果我尝试将 "another_key" 保存到我的模型中,它会毫无问题地存储密钥,但是当我尝试通过 appengine 仪表板中的数据存储查看器访问该实体时,它告诉我它不是有效的钥匙。因此,当我尝试像这样在我的神社模板中使用密钥时:

<a href="{{uri("download", blob=file_key)}}" target="_blank">Export</a>

Ferris 呈现错误 "The resource could not be found." 这是有道理的,因为它显然不是有效的密钥。

所以我想我的问题是,我究竟如何获得在 google 云存储中动态生成的文件的有效密钥?

顺便说一句:通过上传操作获取密钥很容易,但由于某些原因,动态生成的 GCS 对象不会产生相同的结果。

提前致谢

我存储文件名而不是密钥。我存储的文件不是很大,所以在我的应用引擎代码中,我是这样读取它们的:

def get_gcs(fn):
    "Slurps a GCS file and returns it as unicode."
    try:
        with gcs.open(fn, "r") as f:
            return f.read(32*1024*1024).decode("utf-8")
    except gcs.NotFoundError:
        return ""

然后我使用标准应用引擎技术将它们提供给用户。如果你的文件很小,这很好用,但如果你的文件很大,可能有更好的方法。

由于您是通过 App Engine 获取文件,因此即使 ACL 设置为私有也能正常工作。

OK 在阅读 this post 并修改 Kekito 的示例后终于弄明白了。

最终我想做的是允许最终用户从 NDB 数据存储中导出数据。我原本以为我必须生成一个文件,将其放入 google 云存储 (GCS) 或 blobstore,然后提供下载 URL。我发现它比那简单得多。我什至认为您不需要在 GCS 中创建一个文件来执行此操作(即使我的示例确实向 GCS 添加了一个文件)。

我所要做的就是在返回文件之前将 Content-Disposition 添加为附件。这会生成另存为对话框,允许用户确定下载位置。如果没有 content-disposition,CSV/TXT 内容会在浏览器上呈现,如果用户试图在浏览器中进行另存为,唯一的选择是 HTML 并且无法更改(在 Chrome 无论如何)。

import csv
import cloudstorage
@route
def export_users(self):
    # This can be any NDB query
    user_data = self.Meta.Model.get_users(is_active=True)

    # Set the file name 
    filename = '/mydomain.appspot.com/user_list.csv'

    # Create the file
    gcs_file = cloudstorage.open(filename,'w',content_type='text/csv')

    # Setup the CSV file for writing
    writer = csv.writer(gcs_file, delimiter=',')

    # Loop thru the query and write each row to the CSV file
    for user_info in user_data:
        writer.writerow( (str(user_info.user_lname),str(user_info.user_fname)) )

    # Close the file
    gcs_file.close()

    try:
        # Open the file for reading
        with cloudstorage.open(filename, "r") as the_file:
            # This will open the Save-As dialog box so the end-user can choose where to save the file
            self.response.headers["Content-Disposition"] = "'attachment'; filename=user_list.csv"

            # Push the file to the browser
            return the_file.read(32*1024*1024).decode("utf-8")
    except cloudstorage.NotFoundError:
        return "it failed"