фреймворк ferris2.2 движка приложений Google (python), загрузка изображения в облачное хранилище?

Итак.. Это мой код для загрузки изображения с помощью фреймворка Ferris2. Ура мне, это работает. Однако посмотрите, как мне пришлось закомментировать gcs.open(... ? Я не хочу, чтобы это было закомментировано. Мне бы очень хотелось просто загрузить прямо в облачное хранилище с помощью этого вызова и не использовать ничего, связанного с Какой самый простой способ сделать это, учитывая, что я застрял с использованием AClassForm и ferris framework?

class AClassForm(forms.model_form(AClass, exclude=('image_url') ) ):
     image = FileField(u'Image File') 

class AClasses(Controller): 

    class Meta: 

        Model = AClass 

        prefixes = ('admin',) 

        components = (scaffold.Scaffolding, Upload) 

        Form = AClassForm 



    admin_list = scaffold.list 

    admin_view = scaffold.view 

    admin_edit = scaffold.edit 

    admin_delete = scaffold.delete 



    def admin_add(self): 

        self.scaffold.ModelForm = AClassForm 

        self.scaffold.form_encoding = "multipart/form-data"    

        def before_save_callback(controller,container, item): 

            image = self.request.params["image"] 

            object_name = blobstore.parse_file_info(image).gs_object_name.split('/')[-1] 

            upload_settings = settings.get("upload") 

            url =  upload_settings["url"] 

            bucket = upload_settings["bucket"] 

            #send to the cloud 

            #write a task to execute this? 

            item.image_url  =  url % (bucket, object_name) 

            #gcs_file= gcs.open("/".join(["", bucket, object_name]),   

               # 'w', content_type="image/jpeg",  

                #options={'x-goog-acl': 'public-read'} )  

            #gcs_file.write(item.image)#.file.encode('utf-8')) # 

            #gcs_file.close() 

            return 

        self.events.scaffold_before_save += before_save_callback 

        return scaffold.add(self)

person Community    schedule 05.10.2015    source источник


Ответы (2)


Я не знаю, как Ferris работает внутри, но вы можете использовать cloudstorage напрямую.

Моя оболочка хранилища изображений обеспечивает изменение размера и возвращает общедоступный URL-адрес для загрузки для обслуживания непосредственно из хранилища.

import urlparse    
from google.appengine.api import app_identity, blobstore, images
import cloudstorage

class ImageStorage(object):

    def __init__(self, base_uri):
        self.base_uri = "/{}/{}".format(app_identity.get_default_gcs_bucket_name(), base_uri.lstrip('/'))

    def put(self, image, name, mime=None, width=None, height=None):
        """Puts an image into the Google Cloud Storage"""

        if width or height:
            image = images.resize(image, width=width or height, height=height or width)
            mime = 'image/png'  # resize defaults to output_encoding=PNG
        options = {'x-goog-acl': 'public-read'}
        with cloudstorage.open(self.make_key(name), 'w', content_type=mime, options=options) as fp:
            fp.write(image)
        return self.get_url(name)

    def get_url(self, name):
        """Gets the url for an image from Google Cloud Storage"""
        key = self.make_key(name)
        # must be prefixed with /gs for the blob store to know it is from gcs
        # https://cloud.google.com/appengine/docs/python/blobstore/#Python_Using_the_Blobstore_API_with_Google_Cloud_Storage
        url = images.get_serving_url(blobstore.create_gs_key('/gs' + key))

        # s/https/http/ if running under dev_appserver.py
        # if not config.isLocal:
        #    parts = urlparse.urlparse(url)
        #    secure_parts = ('https',) + parts[1:]
        #    url = urlparse.urlunparse(secure_parts)

        return url

    def make_key(self, name):
        """Makes an item name key for Google Cloud Storage"""
        return '%s/%s' % (self.base_uri, name)

Использование внутри подкласса webapp2.RequestHandler. Это сохраняет файл с именем «изображение» в корзине по умолчанию для вашего приложения в облачном хранилище по пути /some/bucket/path/my-image-name.

thumb = self.request.POST["image"]
if hasattr(thumb, 'value'):
    gs_base_uri = '/some/bucket/path'
    image_storage = ImageStorage(gs_base_uri)
    thumb_fn = 'my-image-name'
    session_thumb_url = image_storage.put(image=thumb.value,
                                          name=thumb_fn,
                                          mime=thumb.type,
                                          width=300, height=300)

    return session_thumb_url
person Josh J    schedule 06.10.2015

Насколько я понимаю, если вы используете компонент загрузки Ferris, вы не можете избежать Blobstore, но следующее очень близко. Вам не нужно использовать класс Form, если вы этого не хотите, я сам редко его использую. Итак, представьте себе следующий контроллер:

from ferris import Controller, route
from ferris.components.upload import Upload
import cloudstorage as gcs
from google.appengine.ext import blobstore
import logging


class ImageManager(Controller):
    class Meta:
        components = (Upload,)  

    @route
    def list(self):
        #This just passes the upload URL to use in the form
        self.context['upload_url'] = self.components.upload.generate_upload_url(uri=self.uri('image_manager:image_uploader_action'))


    @route
    def image_uploader_action(self):
        # This gets all of the uploads passed in from the form
        uploads = self.components.upload.get_uploads()

        # This is the raw google cloud object reference. 'myfile' is the name of the upload field in the html form
        file_gcs_obj_name = uploads['myfile'][0].cloud_storage.gs_object_name 

        # This is the blobstore key just for giggles
        file_blobstore_key = uploads['myfile'][0].key()

        # This will get rid of the preceeding junk you don't need i.e. "/gs/yadda/yadda"
        clean_file_name = file_gcs_obj_name[3:]

        # This is the name of the file as it was uploaded by the end-user
        file_name_friendly  = uploads['myfile'][0].filename

        # This is the actual file, with this you can do whatever you want
        the_actual_image = gcs.open(clean_file_name,'r')

        # The file name by default is long and ugly, lets make a copy of the file with a more friendly name
        new_filename = '/mydomain.appspot.com/'+file_name_friendly
        gcs.copy2(clean_file_name,new_filename)

        # We can generate a serving URL by using the blobstore API
        valid_blob_reference = blobstore.create_gs_key('/gs'+new_filename)
        file_serving_url = images.get_serving_url(valid_blob_reference)
        logging.info('the serving url is: %s'% file_serving_url)

        # delete the original image from cloud storage
        gcs.delete(clean_file_name)

        # Delete the original image from blobstore
        blobstore.delete(file_blobstore_key)

        # Close the file
        the_actual_image.close()

        return 'Done. go check the cloud storage browser'

Теперь все, что вам нужно, это HTML-форма. Вы можете использовать что-то вроде этого:

{% extends "layouts/default.html" %}
{% block layout_content %}
<form name="myform" action="{{upload_url}}" method="POST" enctype="multipart/form-data">
    <input type="file" name="myfile" id="fileToUpload">
    <input type="submit" value="Upload File" name="submit">
</form>
{% endblock %}

Феррис по-прежнему собирается разместить файл в хранилище больших двоичных объектов, но вы можете удалить его после использования функции cloudstorage.copy2(). Эта функция довольно новая, поэтому не забудьте обновить пакет cloudstore. Вы можете загрузить последнюю копию с Google или Pypi (https://pypi.python.org/pypi/GoogleAppEngineCloudStorageClient/1.9.22.1) Надеюсь, это поможет.

person user2744119    schedule 06.10.2015
comment
Похоже, вы сделали gcs.open, но никогда не записывали образ, то есть gcs.write(?). Это было специально? Вы знаете, работает ли этот код? - person ; 06.10.2015
comment
Вы абсолютно правы, в моем примере open был совершенно не нужен, потому что компонент Upload уже помещает его в облачный магазин. Единственное, чего не хватает, — это создание URL-адреса для обслуживания (который я обновил). Определенно работает, использовал его сегодня. - person user2744119; 07.10.2015