How do I list all of the files I've uploaded to the datastore?

82 views
Skip to first unread message

Peter S

unread,
May 13, 2016, 9:43:30 PM5/13/16
to Google App Engine

I'm completely new to GAE and trying to figure some things out. I'm trying to write a small app which will allow a user to upload files, and display a list of those files already uploaded. I am having trouble getting my app to list the files already uploaded. 

The code works in so far as it allows me to upload a file, but it does not print the list of files already uploaded. Any ideas where I'm going wrong?

My Code:

from google.appengine.ext import blobstore
from google.appengine.ext import ndb
from google.appengine.ext.webapp import blobstore_handlers
import webapp2

class DatastoreFile(ndb.Model):
    data = ndb.BlobProperty(required=True)
    mimetype = ndb.StringProperty(required=True)
    filename = ndb.StringProperty(required=True)
    timestamp = ndb.DateTimeProperty(required=True,auto_now_add=True)

class MainHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_file')

        files = DatastoreFile.query().order(-DatastoreFile.timestamp)
        for file in files:
            self.response.write('<li> %s' % file.filename)

        self.response.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))

class UploadFile(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        file_data = self.request.POST.get('file_data', None)

        if file_data is not None:
            entity = DatastoreFile(
                data=file_data.value,
                filename=file_data.filename,
                mimetype=file_data.type
            )
            entity.put()
            response = {
                'filename': entity.filename,
                'timestamp': str(entity.timestamp),
                'key': entity.key.urlsafe()
            }


        else: # no files were received
            response = {'error': 'file not received'}
        self.redirect('/')

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload_file', UploadFile),
], debug=True)





Jason Collins

unread,
May 15, 2016, 11:51:42 AM5/15/16
to Google App Engine
I think your <html> and <body> tags are out of order (try doing a View Source on your page to see if the <li> filenames are there). And you should include a <ul>

Just reorder things a bit, something like:

class MainHandler(webapp2.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload_file')

        self.response.write("""
<html><body>
<ul>
""")

        files = DatastoreFile.query().order(-DatastoreFile.timestamp)
        for file in files:
            self.response.write('<li> %s' % file.filename)

        self.response.write("""
</ul>
<form action="{0}" method="POST" enctype="multipart/form-data">
 Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))


Also, look into using templates like Jinja as it will make it much easier to write and debug stuff like this.

Peter S

unread,
May 16, 2016, 5:51:15 PM5/16/16
to Google App Engine
Thanks for that! Seems that it's still not displaying my list though. After some investigation I see that my files are being uploaded to the datastore as __BlobInfo__ objects, and not as my 'DatastoreFile' objects that I had expected. Any ideas why that is happening? Is there something I can do to ensure that they're uploaded a 'DatastoreFile' objects, or failing that, how would I go about listing the __BlobInfo objects which have been uploaded?

Jason Collins

unread,
May 16, 2016, 5:57:55 PM5/16/16
to Google App Engine
The __BlobInfo__ will be written regardless.

So, given that your DatastoreFile entities are not being created, look to the post() method of UploadFile.

The parent class BlobstoreUploadHandler gives you a method called get_uploads() - use this instead of looking at the POST args.

So you have something like:

class UploadFile(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):

Jason Collins

unread,
May 16, 2016, 6:06:18 PM5/16/16
to Google App Engine
[... and now for the exciting conclusion to that last post ....]


class UploadFile(blobstore_handlers.BlobstoreUploadHandler):
   def post(self):
       if self.get_uploads():
            upload = self.get_uploads()[0]  # if you only have one file input on your form
            entity = DatastoreFile(
                data=upload.key(),  # this is the BlobKey
                filename=upload.filename,
                mimetype=upload.content_type
            )
            entity.put()
...

NOTE that you do not get the file bytes themselves. They are "peeled off" the POST request and stored into Blobstore - the key() is the reference to the bytes.

If you want to store bytes directly into Datastore yourself, then you don't want the Blobstore API at all and you need to perform the POST arg processing yourself.

Peter S

unread,
May 18, 2016, 6:12:49 PM5/18/16
to Google App Engine
Only just got a chance to test this out now, but that does indeed fix the problem! 

Thank you so much for your help. I really appreciate it! 
Reply all
Reply to author
Forward
0 new messages