In my GAE app I want to store the uploaded file in a ndb.BlobProperty . How can I assign the uploaded file content to this property.
Further more is BlobProperty the standard approach to store user uploaded files.
Link to similar question
Simply put, assign a serving url that you pass to a handler setup by routes
handlers
class GetBlobstoreUrl(BaseHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload/')
self.response.out.write(upload_url)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads()
blob_info = upload_files[0]
model
class SomeModel(ndb.Model):
avatar = ndb.BlobProperty()
Related
I am newbie on Django and I would like to implement a request that allow to make upload file.
I wrote some code for this, but when I opened the file in local, my computer says it may be damaged.
I don't understand why because the size file is the same to another when i sent with postman.
here is my code :
view.py
def handle_uploaded_file(f):
with open(f.name, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
class FileUploadView(APIView):
parser_classes = (FileUploadParser,)
def put(self, request, filename, format="png"):
file_obj = request.data['file']
handle_uploaded_file(file_obj)
return Response(filename, status.HTTP_201_CREATED)
Not sure if you're writing the files into the system manually but Django already has a way to handle the uploading of files - and DRF just builds on top of that. All you have to do is create a model with a FileField or any field that extends from it.
class Upload(models.Model):
user_upload = models.FileField(upload_to='path/to/upload')
Bear in mind that the database does not store the file - it only stores the path to the file. The file is directly uploaded to the path you've specified in the field. More info about upload_to here.
To upload using DRF - all you have to do is create a serializer using ModelSerializer and use a generic API view like CreateAPIView unless you have other requirements.
Your ModelSerializer can be something like:
class UploadFileSerializer(serializers.ModelSerializer):
class Meta:
model = Upload # reference the model above
fields = '__all__'
And in your views:
class UploadFileView(CreateAPIView):
serializer_class = UploadFileSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, files=request.FILES) # <------ note the request.FILES
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
That should do the trick!
I am working on a django project where i try to upload a file via http post request.
my upload script is :
url=r'http://MYSITEURL:8000/upload'
files={'file':open('1.png','rb')}
r=requests.post(url,files=files)
my receiving side is in my django site , in views.py:
def upload_image(request):
from py_utils import open_py_shell;open_py_shell.open_py_shell()
when i do request.FILES i can see all the post details,
what i want to know is how to save it in the server side once i got the post request
What you have in request.FILES is InMemoryUploadedFile. You just need to save it somewhere in file system.
This is example method taken from Django docs:
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
I think you can work with models well. It will be the right way for Django. Here is an example, models.py file:
from django.db import models
from django.conf import settings
import os
import hashlib
def instanced_file(instance, filename):
splitted_name = filename.split('.')
extension = splitted_name[-1]
return os.path.join('files', hashlib.md5(str(instance.id).encode('UTF-8')).hexdigest() + '.' + extension)
class File(models.Model):
name = models.FileField('File', upload_to = instanced_file)
def get_file_url(self):
return '%s%s' % (settings.MEDIA_URL, self.name)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
After the creating models create forms and go on.
I have the following code (taken from the sample code) to upload files directly to GCS but it does not preserve the file name of the original file. Instead it stored using a hash as the filename like
'L2FwcGhvc3RpbmdfcHJvZC9ibG9icy9BRW5CMlVxd3BLMk1ZVVg0SVVzSTlUQTMzRzEyVzQ3ZHQtQy1JSjh6ZU5aT0hWc3FzZ2k0NXpfNXZBUTZDRThSQTFNNi0xX0dEY1M4MEFwUFJYbGt4cUkxNkRpeGp6M0VUQS51QlBNM3BJNG9qXy0zVHZF'
The problem is that I need to show all the files uploaded to GCS to users so need to preserve the file identity to distinguish the files. They won't be able to identify their uploads from hashes
Here's the sample code... how do I ensure that it uploads with the file name provided? For instance, if I upload a file 'log.csv', it is uploaded as 'log.csv' rather than a hash which doesn't say if it's the file or not.
import os
import urllib
import webapp2
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
class MainHandler(webapp2.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload', gs_bucket_name='uploads')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit"
name="submit" value="Submit"> </form></body></html>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
resource = str(urllib.unquote(resource))
blob_info = blobstore.BlobInfo.get(resource)
self.send_blob(blob_info)
app = webapp2.WSGIApplication([('/', MainHandler),
('/upload', UploadHandler),
('/serve/([^/]+)?', ServeHandler)],
debug=True)
The filename and other metadata are in the BlobInfo object in the datastore, not in the blobstore per se. See https://cloud.google.com/appengine/docs/python/blobstore/blobinfoclass for all details of the BlobInfo class (and https://cloud.google.com/appengine/docs/python/tools/webapp/blobstorehandlers for how the provided handlers deal with it on both upload and download).
So, instead of requiring the user to pass you the blob key (so you can use blobstore.BlobInfo.get(resource) directly on the request), you can allow the user to pass you the filename, use BlobInfo.gql to give you all the blobinfo objects for the given filename (no guarantee of uniqueness, of course -- unless you enforce it yourself in the app at upload time by rejecting duplicate filenames), then use the key() method of those blob info objects to get the required blob keys.
Access to the datastore (for blobs' metadata) is faster than access all the way to the blobstore, so e.g to present a list of uploaded files, BlobInfo.all() (returning a query to which you can add filters) will let you present filenames & other metadata (content type, creation datetime, size in bytes) to your users, for them to select which blob(s) they want to retrieve.
I am am using Google App Engine in Python and I want users to be able to upload a video, which is functioning properly by following their basic example but then I want to be able to get the user to add additional information about the video, like the title and category and a summary while it is uploading. Is there any way I can make the upload asynchronous so that the user doesn't have to wait the whole time the video is uploading?
I know about the create_upload_url_async() method but that doesn't do what I am trying.
Right now I have the following which uploads and serves but I want to make an intermediate step where the user can add the info preferably on the same screen as the UploadHandler while it is uploading.
class VideoHandler(BlogHandler):
def get(self):
user = self.get_user()
upload_url = blobstore.create_upload_url('/uploadingvideo')
self.render('videohandler.html', user=user, upload_url=upload_url)
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
blob_key = str(urllib.unquote(blob_key))
if not blobstore.get(blob_key):
self.error(404)
else:
self.send_blob(blobstore.BlobInfo.get(blob_key))
I'd be glad to provide more information if you need it.
this has been troubling me alot too clifgray. the solution is to build your form around the blob form.
Here's google's example on how to submit data to the blob store.
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
Just remove the self redirect bit at the bottom of the code and add some code to handle your form.
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.video = str(blob_info.key())
greeting.content = self.request.get('content')
greeting.put()
Your form in your django template should look something like this:
form action="{{ upload_url }}" enctype="multipart/form-data" method="post">
textarea name="content" placeholder="write something about this video.." tabindex="1" rows="2" cols="40"></textarea>
input name="file" type="file" >
input name="submit" type="submit" value="Submit" />
/form>
There you have it. hope this helps
I'm trying to associate a video file to a record with a bunch of properties, but can't seem to allow the user to do everything in one form - name the video, provide description and answer some question, AND upload the file.
Here are the steps I'd like to perform:
User is served with a page containing a form with the following fields: Name, Description, File selector.
The file gets stored as a blob and the id gets recorded together with name and description.
Does anyone have any examples of doing this I could learn from or a tutorial you could point me to? The one from google only shows uploading the file and getting redirected to it.
Thanks and sorry for a newbish question!
http://demofileuploadgae.appspot.com/ - My demo uploader to the blobstore.
My code for the upload: http://code.google.com/p/gwt-examples/source/browse/trunk/DemoUpload/src/org/gonevertical/upload/#upload/server%3Fstate%3Dclosed
Here's the code I'm using to upload images and associate them with articles. The toughest bit was getting the article id to get to the upload handler, I solved it by setting the file name as the article id to get around the problem.
from lib import urllib2_file
from lib.urllib2_file import UploadFile
# this view serves a task in a queue
def article(request):
article = Article.objects.get(id=form.cleaned_data['article'])
try:
image = StringIO(urllib2.urlopen(image_url).read())
except (urllib2.HTTPError, DownloadError):
article.parsed = True
article.save()
else:
image = UploadFile(image, '.'.join([str(article.id), image_url.rsplit('.', 1)[1][:4]]))
upload_url = blobstore.create_upload_url(reverse('Articles.views.upload'))
try:
urllib2.urlopen(upload_url, {'file': image})
except (DownloadError, RequestTooLargeError):
pass
return HttpResponse(json.dumps({'status': 'OK'}))
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
def upload(request):
if request.method == 'POST':
blobs = get_uploads(request, field_name='file', populate_post=True)
article = Article.objects.get(id=int(blobs[0].filename.split('.')[0]))
article.media = blobs[0].filename
article.parsed = True
article.save()
return HttpResponseRedirect(reverse('Articles.views.upload'))
else:
return HttpResponse('meow')
# this serves the image
def image(request):
blob = BlobInfo.gql("WHERE filename='%s' LIMIT 1" % request.form.cleaned_data['id'])[0]
return HttpResponse(BlobReader(blob.key()).read(),
content_type=blob.content_type)
Also you'll need this http://fabien.seisen.org/python/urllib2_file/
Here is how I did it. It is more straight forward than you think. Note the following taken from Blobstore overview.
"When the Blobstore rewrites the user's request, the MIME parts of the uploaded files have their bodies emptied, and the blob key is added as a MIME part header. All other form fields and parts are preserved and passed to the upload handler." In the upload handler is where you can do whatever it is you want with the other form fields.
class Topic(db.Model):
title = db.StringProperty(multiline=False)
blob = blobstore.BlobReferenceProperty()
imageurl = db.LinkProperty()
class MainHandler(webapp.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File: <input type="file" name="file"><br>
<div><label>Title:</label></div>
<div><textarea name="title" rows="1" cols="25"></textarea></div><input type="submit"
name="submit" value="Submit"> </form>""")
self.response.out.write('<br><br><h2>TOPIC LIST</h2><table border="1"><tr><td>')
for topic in Topic.all():
self.response.out.write('<div><img src="%s=s48"/>' % topic.imageurl)
self.response.out.write('<div><b>Image URL: </b><i>%s</i></div>' % topic.imageurl)
self.response.out.write('<div><b>Title: </b><i>%s</i></div>' % topic.title)
self.response.out.write('</td></tr></table><br>')
self.response.out.write('</body></html>')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
topic = Topic()
topic.title = self.request.get("title")
topic.blob = blob_info.key()
topic.imageurl = images.get_serving_url(str(blob_info.key()))
topic.put()
self.redirect('/')
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
], debug=True)
run_wsgi_app(application)