【问题标题】:Google App Engine: Displaying images stored in the datastoreGoogle App Engine:显示存储在数据存储区中的图像
【发布时间】:2014-04-12 07:43:18
【问题描述】:

我创建了一个实体“图像”,它存储了文件名和一个用于存储图像的 blob 对象:

class Images(ndb.Model):
    file_name = ndb.StringProperty()
    blob = ndb.BlobProperty()

现在,我尝试在我的应用程序中显示“database.jpeg”图像,如下所示:

HTML 表单

<html>
<head>
    <title>Template</title>
</head>
<body>
    <img src="/img_serve/database.jpeg" /> 
</body>
</html>

Python 文件:

class ImgServe(Handler):
    def get(self, resource):
        image = ndb.Key('Images', resource).get()
        self.response.headers[b'Content-Type'] = mimetypes.guess_type(image.file_name)[0]
        self.response.write(image.blob)  

app = webapp2.WSGIApplication([('/', MainPage),
                                ('/signup', Register),
                                ('/login', Login),
                                ('/logout', Logout),
                                ('/mp', MP),
                                (r'/file_upload', FileUpload),
                                ('/blob', Blob),
                                (r'/img_serve/<resource:(.*)>', ImgServe),
                                ('/template', Template)], debug=True)

这是“图像”实体的屏幕截图:

但是,我的应用程序中的图像损坏。我的代码中似乎有什么问题?


整个代码:

main.py

import os
import re
import random
import hashlib
import hmac
from string import letters
import mimetypes
import webapp2
import jinja2

from google.appengine.ext import ndb

template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir),
                               autoescape = True)

secret = 'fart'

def render_str(template, **params):
    t = jinja_env.get_template(template)
    return t.render(params)

def make_secure_val(val):
    return '%s|%s' % (val, hmac.new(secret, val).hexdigest())

def check_secure_val(secure_val):
    val = secure_val.split('|')[0]
    if secure_val == make_secure_val(val):
        return val

class Handler(webapp2.RequestHandler):
    def write(self, *a, **kw):
        self.response.out.write(*a, **kw)

    def render_str(self, template, **params):
        params['user'] = self.user
        return render_str(template, **params)

    def render(self, template, **kw):
        self.write(self.render_str(template, **kw))

    def set_secure_cookie(self, name, val):
        cookie_val = make_secure_val(val)
        self.response.headers.add_header(
            'Set-Cookie',
            '%s=%s; Path=/' % (name, cookie_val))

    def read_secure_cookie(self, name):
        cookie_val = self.request.cookies.get(name)
        return cookie_val and check_secure_val(cookie_val)

    def login(self, user):
        self.set_secure_cookie('user_id', str(user.key().id()))

    def logout(self):
        self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/')

    def initialize(self, *a, **kw):
        webapp2.RequestHandler.initialize(self, *a, **kw)
        uid = self.read_secure_cookie('user_id')
        self.user = uid and User.by_id(int(uid))

class MainPage(Handler):
    def get(self):
        self.render("home.html")

##### user stuff
def make_salt(length = 5):
    return ''.join(random.choice(letters) for x in xrange(length))

def make_pw_hash(name, pw, salt = None):
    if not salt:
        salt = make_salt()
    h = hashlib.sha256(name + pw + salt).hexdigest()
    return '%s,%s' % (salt, h)

def valid_pw(name, password, h):
    salt = h.split(',')[0]
    return h == make_pw_hash(name, password, salt)

def users_key(group = 'default'):
    return ndb.Key.from_path('users', group)

class Images(ndb.Model):
    file_name = ndb.StringProperty()
    blob = ndb.BlobProperty()

class User(ndb.Model):
    name = ndb.StringProperty(required = True)
    pw_hash = ndb.StringProperty(required = True)
    email = ndb.StringProperty()

    @classmethod
    def by_id(cls, uid):
        return User.get_by_id(uid, parent = users_key())

    @classmethod
    def by_name(cls, name):
        u = User.all().filter('name =', name).get()
        return u

    @classmethod
    def register(cls, name, pw, email = None):
        pw_hash = make_pw_hash(name, pw)
        return User(parent = users_key(),
                    name = name,
                    pw_hash = pw_hash,
                    email = email)

    @classmethod
    def login(cls, name, pw):
        u = cls.by_name(name)
        if u and valid_pw(name, pw, u.pw_hash):
            return u


USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
    return username and USER_RE.match(username)

PASS_RE = re.compile(r"^.{3,20}$")
def valid_password(password):
    return password and PASS_RE.match(password)

EMAIL_RE  = re.compile(r'^[\S]+@[\S]+\.[\S]+$')
def valid_email(email):
    return not email or EMAIL_RE.match(email)

class Signup(Handler):
    def get(self):
        self.render("signup-form.html")

    def post(self):
        have_error = False
        self.username = self.request.get('username')
        self.password = self.request.get('password')
        self.verify = self.request.get('verify')
        self.email = self.request.get('email')

        params = dict(username = self.username,
                      email = self.email)

        if not valid_username(self.username):
            params['error_username'] = "That's not a valid username."
            have_error = True

        if not valid_password(self.password):
            params['error_password'] = "That wasn't a valid password."
            have_error = True
        elif self.password != self.verify:
            params['error_verify'] = "Your passwords didn't match."
            have_error = True

        if not valid_email(self.email):
            params['error_email'] = "That's not a valid email."
            have_error = True

        if have_error:
            self.render('signup-form.html', **params)
        else:
            self.done()

    def done(self, *a, **kw):
        raise NotImplementedError

class Register(Signup):
    def done(self):
        #make sure the user doesn't already exist
        u = User.by_name(self.username)
        if u:
            msg = 'That user already exists.'
            self.render('signup-form.html', error_username = msg)
        else:
            u = User.register(self.username, self.password, self.email)
            u.put()

            self.login(u)
            self.redirect('/')

class Login(Handler):
    def get(self):
        self.render('login-form.html')

    def post(self):
        username = self.request.get('username')
        password = self.request.get('password')

        u = User.login(username, password)
        if u:
            self.login(u)
            frontuser = username
            self.render('home.html', frontuser = frontuser)
        else:
            msg = 'Invalid login'
            self.render('login-form.html', error = msg)

class Logout(Handler):
    def get(self):
        self.logout()
        self.redirect('/')

class MP(Handler):
    def get(self):
        self.render('mp.html')

class FileUpload(Handler):
    def post(self):
        file_upload = self.request.POST.get("file", None)
        file_name = file_upload.filename
        image = Images(id=file_name, file_name=file_name, blob=file_upload.file.read())
        image.put()

        self.response.headers[b'Content-Type'] = mimetypes.guess_type(image.file_name)[0]
        self.response.write(image.blob)

class ImgServe(Handler):
    def get(self, resource):
        image = ndb.Key('Images', resource).get()
        self.response.headers[b'Content-Type'] = mimetypes.guess_type(image.file_name)[0]
        self.response.write(image.blob)            

class Blob(Handler):
    def get(self):
        self.render("blob.html")

class Template(Handler):
    def get(self):
        self.render('template.html')


app = webapp2.WSGIApplication([('/', MainPage),
                                ('/signup', Register),
                                ('/login', Login),
                                ('/logout', Logout),
                                ('/mp', MP),
                                (r'/file_upload', FileUpload),
                                ('/blob', Blob),
                                (r'/img_serve/<resource:(.*)>', ImgServe),
                                ('/template', Template)], debug=True)

blob.html

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Image Upload</title>
</head>
<body>
<form action="/file_upload" enctype="multipart/form-data" method="post">
    <div><input type="file" name="file"/></div>
    <div><input type="submit" value="Upload"></div>
</form>
</body>
</html>

模板.html

<html>
<head>
    <title>Template</title>
</head>
<body>
    <img src="/img_serve/database.jpeg" /> 
</body>
</html>

另外,这是我得到的,而不是图像:

【问题讨论】:

  • 您是否尝试过直接获取图像。你得到的是 404,还是得到数据但没有被解释为图像?
  • 还有你是如何创建图像的。您的数据存储查看器显示键具有自动生成的 id,因此数字 id 是“资源”值,.如果您想使用显示的代码检索图像,您可能应该使用“database.jpg”作为键来创建图像。
  • 我在我的原始帖子中包含了更多信息,可以回答您上面的问题。此外,通过使用数字 id 作为资源值,问题似乎并没有消失。这是我所做的: 其中该数值是“database.jpeg”的 ID。
  • 在你的.py代码中:图片上传后是否显示?在此代码中,file_name 用于 id。
  • 您上面的代码与 DataViewer 不匹配。在屏幕截图中,您有数字 id 但是您的代码明确地将 id 设置为文件名。它必须是其中之一。如果您的数据查看器显示数字 ID,则说明您的代码有问题或屏幕截图已过期。

标签: python google-app-engine blob blobstore


【解决方案1】:

我建议您使用 Blobstore 来存储图像 - 它更便宜,并且专门为此目的进行了优化。

更好的是,您可以将图像存储在 Google Cloud Storage 中。它甚至比 Blobstore 便宜。

这两种解决方案都提供了一个额外的好处 - 浏览器将能够缓存这些图像。

【讨论】:

  • 我同意。但是 1) 谷歌正在远离 blovstore 2) 免费应用程序引擎应用程序的谷歌云存储实现尚未完成 3) 对于小图像和其他类型的 blob,他的代码可以工作,但对于图像来说非常不理想。
  • 您可以在任何应用程序中使用 GCS,无论是否免费。
  • 是的,但是有各种各样的问题,比如在 SDK(本地 clodstorage)中使用它并使用 : options={b'x-goog-acl': b'public-read 将其公开'} 不起作用。
  • 我没有这些问题。
【解决方案2】:

使用 App 引擎 SDK 1.9.0 和 Python 27,在使用您的上传代码和文件名上传图像后,SDK 数据存储应如下所示:clock.png.

在您的代码中:class FileUpload(Handler)class ImgServe(Handler):

但是为什么不使用 webapp2.RequestHandler 作为 Handler 呢?

使用这个静态 HTML:

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Image Serving</title>
</head>
<body>
   <img src="/img_serve/clock.png" alt="clock" >
</body>
</html>

还有这个处理程序:

class ImgServe(webapp2.RequestHandler):

    def get(self, resource):
        image = ndb.Key('Images', resource).get()
        self.response.headers[b'Content-Type'] = mimetypes.guess_type(image.file_name)[0]
        self.response.write(image.blob)

路由:

    webapp2.Route(r'/img_serve/<resource:(.*)>', handler=....ImgServe)

【讨论】:

  • 我已经有了...这是我的代码中定义类 Handler 的方式:类 Handler(webapp2.RequestHandler)。我现在已经在我的原始帖子中包含了整个代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-11
  • 2011-02-16
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-20
相关资源
最近更新 更多