Overwritting Data in App Engine - python

I have a function that gets an image from a form, and put's it into the database along with the username. So, here is my database:
class Imagedb(db.Model):
name = db.StringProperty(required = True)
image = db.BlobProperty()
And here is the code that writes to the database:
class Change_Profile_Image(MainHandler):
def get(self):
if self.user:
self.render('change_profile_image.html', username = self.user.name, firstname=self.user.first_name)
else:
self.render('change_profile_image.html')
def post(self):
imagedb = Imagedb(name = self.user.name)
imageupl = self.request.get("img")
imagedb.image = db.Blob(imageupl)
imagedb.put()
self.redirect('/profile')
Any who, it works awesome. Except for one thing. What i'm trying to accomplish is only storing ONE profile picture. What ends up happening is this:
Say I am the user admin. Ill upload a display pic, that pic shows in the profile. Ill upload another one, that one shows. Cool, except for the fact that I have 2 objects in my database that have the name = admin attribute. I would like to edit this...
def post(self):
imagedb = Imagedb(name = self.user.name)
imageupl = self.request.get("img")
imagedb.image = db.Blob(imageupl)
imagedb.put()
self.redirect('/profile')
so that I can post images to the database, but if one exists, it is overwritten. Could anyone help me with this please? I'm relatively new to python and app engine.
If something is unclear, please let me know.

You want to set the key of the Imagedb entity to "name". Essentially, you don't need the name field, but you'll instantiate it like
imagedb = Imagedb(key_name = self.user.name)
The key is a required field on all entities. By using your user name as the key it means every time you refere to a given key, it's the same entity.

Related

How to display an image/pdf file stored in mongodb in browser using flask?

can anyone help me to display an image or pdf file stored in mongodb with a flask app to the browser? Currently, when I try, I get a 200 response but the browser is just blank. This is the function I use:
My mongo document is modeled like this:
class Users(db.Document):
_id = db.StringField()
name = db.StringField()
picture = db.ReferenceField('fs.files') #holds the reference for the file in the database
upload_picture = db.FileField() #used to load pics via flask into the database
email = db.StringField()
password = db.StringField()
meta = {'collection': 'Users'}
This is the function I had to retrieve and display the image. However with this function, I get a blank browser:
class RetrievePicture(Resource):
def get(self, id):
try:
user = Users.objects(_id=id).first()
doc = user.picture.read()
return send_file(io.BytesIO(doc), mimetype='image/png')
except Users.DoesNotExist:
return 'Picture not found', 401
The flask route I enter into the browser is supposed to return the picture from the specific user whose id I enter. The route looks like this http://127.0.0.1:5000/api/picture/(id) Does anyone know what I'm doing wrong or have another solution using MongoEngine?

GAE + NDB + Blobstore + Google High Performance Image Serving

I'm making an app to upload text and images. I've readed a lot about blobstore and Google High Performance Image Serving and finally I got a way to implement it all together.
What I want to know is if all is well done or can be do in a better way, and also if it is better to save the serving_url in the model or must be calculated every time I want to print the images in the page.
There is a User and a Picture only.
This is the code (summarized, forget about my custom.PageHandler, that only have functions to render the pages easily, and the stuff for check forms values, etc.):
class User(ndb.Model):
""" A User """
username = ndb.StringProperty(required=True)
password = ndb.StringProperty(required=True)
email = ndb.StringProperty(required=True)
class Picture(ndb.Model):
""" All pictures that a User has uploaded """
title = ndb.StringProperty(required=True)
description = ndb.StringProperty(required=True)
blobKey = ndb.BlobKeyProperty(required=True)
servingUrl = ndb.StringProperty()
created = ndb.DateTimeProperty(auto_now_add=True)
user = ndb.KeyProperty(kind=User)
# This class shows the user pics
class List(custom.PageHandler):
def get(self):
# Get the actual user pics
pics = Picture.by_user(self.user.key)
for pic in pics:
pic.servingUrl = images.get_serving_url(pic.blobKey, size=90, crop=True)
self.render_page("myPictures.htm", data=pics)
# Get and post for the send page
class Send(custom.PageHandler, blobstore_handlers.BlobstoreUploadHandler):
def get(self):
uploadUrl = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", form_action=uploadUrl)
def post(self):
# Create a dictionary with the values, we will need in case of error
templateValues = self.template_from_request()
# Test if all data form is valid
testErrors = check_fields(self)
if testErrors[0]:
# No errors, save the object
try:
# Get the file and upload it
uploadFiles = self.get_uploads('picture')
# Get the key returned from blobstore, for the first element
blobInfo = uploadFiles[0]
# Add the key to the template
templateValues['blobKey'] = blobInfo.key()
# Save all
pic = Picture.save(self.user.key, **templateValues)
if pic is None:
logging.error('Picture save error.')
self.redirect("/myPics")
except:
self.render_page("customMessage.htm", custom_msg=_("Problems while uploading the picture."))
else:
# Errors, render the page again, with the values, and showing the errors
templateValues = custom.prepare_errors(templateValues, testErrors[1])
# The session for upload a file must be new every reload page
templateValues['form_action'] = blobstore.create_upload_url('/addPic')
self.render_page("addPicture.htm", **templateValues)
Basically, I list all the pics, showing the image in a jinja2 template with this line:
{% for line in data %}
<tr>
<td class="col-center-data"><img src="{{ line.servingUrl }}"></td>
So in the List class I calculate each serving url and add it temporarily to the Model. I don't know exactly if will be good to save it directly in the Model, because I don't know if the url can change with the time. Will be the url permanent for the image? In that case I can save it instead of calculate, true?
The Send class only shows a form to upload the image and saves the data to the Model. I always generate a new form_action link in the case of re-render the page, because docs talk about it. Is it right?
The code is working, but I want to know which is the better way to do it, in terms of performance and resource-saving.
You're right. You do want to save the get_serving_url() instead of calling it repeatedly. It stays the same.
Note that there's a delete_serving_url() when you're done with the url, like when you delete the blob.

How to save an embedded object in GAE?

I'm trying to save a datastore entity reference within another:
class Save(webapp2.RequestHandler):
def get(self):
order = Order(parent=ndb.Key('Orders', 'default_orders'))
order.special_request = self.request.get('specialRequirement')
order.product_type = self.request.get('productType')
customer = Customer(parent=ndb.Key('Customer', 'default_customers'))
customer.name = self.request.get('customerName')
customer.email = self.request.get('email')
customer.put()
order.customer = customer
order.put()
The Customer class is simply:
from google.appengine.ext import ndb
class Customer(ndb.Model):
name = ndb.StringProperty()
email = ndb.StringProperty()
Whilst I've done similar with Rails and mongodb before, I'm not sure what this is called in GAE and am having a hard time searching for examples.
Ok, the following seems to have been my oversight, simply passing the key as:
oder.customer = customer.key
I now have a usable reference to the embedded object and both are being saved correctly.

Profile Pictures Disappeared. Mystery here - GAE (Python)

Ok, first I want to state that this is Google App Engine via Python.
Any who,
These are my handlers / routing where the problem is occuring. Please read below for context and specifics:
class GetImage(MainHandler):
def get(self):
img = db.get(self.request.get("entity_id"))
self.response.out.write(img.image)
class Profile(MainHandler):
def get(self, profile_name):
current_user = str(self.user.name)
profile_name = current_user
if self.user:
key='ag5kZXZ-c3VpdGVnYW1lcnINCxIHSW1hZ2VkYhgxDA'
imgs = db.GqlQuery("select * from Imagedb WHERE name =:1", current_user)
for img in imgs:
key = img.key() # this is the key
self.render('profile.html', profile_name = self.user.name, current_user = self.user.name, profile_image = key ,username = self.user.name, email = self.user.email, first_name = self.user.first_name, last_name = self.user.last_name, country = self.user.country, prov_state = self.user.prov_state, city_town = self.user.city_town)
else:
self.redirect('/register')
class Change_Profile_Image(MainHandler):
def get(self):
if self.user:
self.render('change_profile_image.html', username = self.user.name, firstname=self.user.first_name, current_user = self.user.name)
else:
self.render('change_profile_image.html')
def post(self):
imagedb = Imagedb(name = self.user.name)
imageupl = images.resize(self.request.get("img"), 200, 200)
imagedb.image = db.Blob(imageupl)
imagedb.put()
self.redirect('/profile/'+self.user.name)
app = webapp2.WSGIApplication([('/', MainPage),
('/register', Register),
('/article', ArticlePage),
('/profile/([^/]+)', Profile),
('/login', Login),
('/logout', Logout),
('/welcome', Unit3Welcome),
('/games', Games),
('/forum', Forum),
('/media', Media),
('/rank', Rank),
('/review', Reviews),
('/events', Events),
('/alreadyloggedin', AlreadyLoggedIn),
('/change_profile_image', Change_Profile_Image),
('/img', GetImage)],
debug=True)
Alright so here is where stuff gets loopy. If I change the Profile class to take -- get(self) and remove my reg expression from the routing for the profile class, my images work perfectly. As soon as I route to unique profiles, i.e. pass profile_name into the Profile handler and map the URL to that profile, I lose all functionality of my GetImage handler. When I look at the source code, nothing has changed. The image is still being passed into the template as per usual.
Does anyone have any idea as to what is going on here? I would really appreciate it. Thank you very much in advance. Hopefully my knowledge will catch up to you guys and I'll be answering questions soon :p.
It's difficult to answer your question without seeing a (simplified) version of your template.
There are also a couple of weird elements in your code that make it hard to tell what's going on. It's hard to format this as a comment, so I'm putting it as an answer, just so you can at least see it.
In your get request in your profile handler, you try to get the current user before you check that the current user exists. You also just throw away the profile_name element completely when you assign profile_name to current_user, so you'll never get a profile image for anything but the current user on a profile page.
You take in profile_name here, but never use it:
def get(self, profile_name):
current_user = str(self.user.name)
profile_name = current_user
You loop over imgs but replace the key each time, which means that if you return more than 1 image you can't tell that this has occurred and you overwrite anything but the last image in the query. One thing you should do is add a check to see if imgs is even truthy, so you can tell if you got any results whatsoever, that might (though I can't imagine how) explain why your image handler is failing.
Finally, you might check your source to see which image url is actually being requested in the template.

How to delete a many to many object without deleting all objects within the relationship?

In models.py I have...
class Siteinfo(models.Model):
url = models.CharField(max_length=100)
description = models.TextField()
class Makesite(models.Model):
sitename = models.CharField(max_length=100, unique = True)
siteinfo = models.ManyToManyField(Siteinfo)
ref_id = models.ManyToManyField(RefID)
def __unicode__(self):
return u'%s' %(self.sitename)
I'm trying to delete a instance of description and replace it with another instance and still have it be associated with the same url and still be the many to many object under say. Group on.
So group1 is the site name. to create the relation I have
url = request.POST['url']
description = request.POST['description']
datsite = Makesite.objects.get(sitename=site)
datsite.siteinfo.add(Siteinfo.objects.create(url=url,description=description))
But then when I try to delete and replace the description with this bit of code it also deletes the url.
name = Makesite.objects.get(sitename=site).siteinfo.values_list('description',flat=True)[0]
Makesite.objects.get(sitename=site).siteinfo.get(description=name).delete()
I guess I could try to write some code that could get around this problem but I'd rather find a way to just delete one and add another instance in its place.
Just to be picky, you should be using forms for processing user input.
It sounds like you want to be updating an instance, not deleting and adding one nearly exactly the same.
site_info = Makesite.objects.get(sitename=site).siteinfo.get(description=name)
site_info.description = "new description"
site_info.save()
Or, more simply:
site_info = Siteinfo.objects.get(makesite__sitename=site, description=name) # only 1 query
site_info.description = "new description"
site_info.save()

Categories

Resources