【问题标题】:Saving image file on filesystem on Google App Engine with Python Flask使用 Python Flask 在 Google App Engine 上的文件系统上保存图像文件
【发布时间】:2019-11-27 19:45:08
【问题描述】:

我有一个 Flask 应用程序,用户可以在其中上传图像,图像保存在文件系统的静态文件夹中。 目前,我正在使用 Google App Engine 进行托管,发现无法保存到标准环境中的静态文件夹。这是代码

def save_picture(form_picture,name):
    picture_fn = name + '.jpg'
    picture_path = os.path.join(app.instance_path, 'static/image/'+ picture_fn)
    output_size = (1000,1000)
    i = Image.open(form_picture)
    i.thumbnail(output_size)
    i.save(picture_path)
    return picture_path

@app.route('/image/add', methods=['GET', 'POST'])
def addimage():
    form = Form()
    if form.validate_on_submit():
        name = 'randomname'
        try:
            picture_file = save_picture(form.image.data,name)
            return redirect(url_for('addimage'))
        except:
            flash("unsuccess")
            return redirect(url_for('addimage'))

我的问题是,如果我从标准环境更改为弹性环境,是否可以保存到静态文件夹?如果不是,我应该考虑哪些其他托管选项?你有什么建议吗?

提前致谢。

听从您的建议,我将改用 Cloud Storage。我想知道我应该从upload_from_file()、upload_from_filename() 或upload_from_string() 使用什么。 source_file 从flask-wtform 的form.photo.data 中获取数据。我还没有成功保存在云存储上。这是我的代码:

def upload_blob(bucket_name, source_file, destination_blob_name):
storage_client = storage.Client()
bucket = storage_client.get_bucket(bucket_name)

blob = bucket.blob(destination_blob_name)

blob.upload_from_filename(source_file)

return destination_blob_name

@app.route('/image/add', methods=['GET', 'POST'])
def addimage():
form = Form()
if form.validate_on_submit():
    name = 'randomname'
    try:
        filename = 'foldername/'+ name + '.jpg'
        picture_file = upload_blob('mybucketname', form.photo.data, filename)
        return redirect(url_for('addimage'))
    except:
        flash("unsuccess")
        return redirect(url_for('addimage'))

我已通过更改 save_picture 功能成功地将文件保存在谷歌云存储上,以防万一将来有人遇到此问题:

app.config['BUCKET'] = 'yourbucket'
app.config['UPLOAD_FOLDER'] = '/tmp'

def save_picture(form_picture,name):
    picture_fn = secure_filename(name + '.jpg')
    picture_path = os.path.join(app.config['UPLOAD_FOLDER'], picture_fn)
    output_size = (1000,1000)
    i = Image.open(form_picture)
    i.thumbnail(output_size)
    i.save(picture_path)

    storage_client = storage.Client()
    bucket = storage_client.get_bucket(app.config['BUCKET'])
    blob = bucket.blob('static/image/'+ picture_fn)
    blob.upload_from_filename(picture_path)

    return picture_path

【问题讨论】:

    标签: google-app-engine flask python-3.7 cloud-hosting


    【解决方案1】:

    将它存储到某个文件夹的问题在于它会存在于该实例上,而其他实例将无法访问它。此外,GAE 中的实例来来去去,因此您最终会丢失图像。

    您应该为此使用 Google Cloud Storage:

    from google.cloud import storage
    client = storage.Client()
    bucket = client.get_bucket('bucket-id-here')
    blob = bucket.get_blob('remote/path/to/file.txt')
    blob.upload_from_string('New contents!')
    

    https://googleapis.dev/python/storage/latest/index.html

    【讨论】:

    • 我只需要在我的 GAE Flask 项目中读/写一个很小的 ​​JSON 文件,我是否必须使用谷歌云存储?
    • App Engine 实例的文件系统不是持久的,并且无法被其他正在运行的实例访问,因此您仍然会遇到同样的问题。由于它很小,您可以将此文件作为实体存储在 Datastore 中。当您需要它时,只需获取它并将其格式化为使用它的 json 字符串。
    • 感谢您的快速回复!我是 GAE 的新手,在哪里可以找到一些 Datastore 使用示例?
    • 这是他们的文档。这是指向如何保存实体 cloud.google.com/datastore/docs/concepts/… 的链接
    【解决方案2】:

    使用 Flask 和 Appengine,Python3.7,我通过以下方式将文件保存到存储桶中,因为我想为许多文件循环它:

    for key, upload in request.files.items():
        file_storage = upload
        content_type = None
        identity = str(uuid.uuid4()) # or uuid.uuid4().hex
        try:
            upload_blob("f00b4r42.appspot.com", request.files[key], identity, content_type=upload.content_type)
    

    辅助函数:

    from google.cloud import storage
    
    def upload_blob(bucket_name, source_file_name, destination_blob_name, content_type="application/octet-stream"):
        """Uploads a file to the bucket."""
        storage_client = storage.Client()
        bucket = storage_client.get_bucket(bucket_name)
        blob = bucket.blob(destination_blob_name)
        blob.upload_from_file(source_file_name, content_type=content_type)
        blob.make_public()
    
        print('File {} uploaded to {}.'.format(
            source_file_name,
            destination_blob_name))
    

    【讨论】:

    • storage_client = storage.Client() 移到函数外不是更好吗?您只需要创建一次,而不是每次调用该函数。
    • @gaefan 是的,确实是这样......感谢您指出这一点。
    【解决方案3】:

    从 Google App Engine 标准环境更改为 Google App Engine 灵活环境将允许您写入磁盘,以及为您的特定应用程序选择具有更多内存的 Compute Engine 机器类型 [1]。如果您对遵循此路径感兴趣,请从迁移 Python 应用程序here 中找到所有相关文档。

    尽管如此,正如用户 @Alex 在他提供的答案中解释的那样,根据您的负载创建实例(实例数量增加)或删除(实例数量减少),更好的选择您的特殊情况是使用云存储。查找使用 Python here 将对象上传到 Cloud Storage 的示例。

    【讨论】:

      猜你喜欢
      • 2013-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 2017-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多