9

am trying yo do this using tornado and pil and mongodb.

avat = self.request.files['avatar'][0]["body"]
nomfich = self.request.files['avatar'][0]["filename"]

try:
    image = Image.open(StringIO.StringIO(buf=avat))
    size = image.size
    type = image.format

    avatar = r"/profile-images/{0}/{1}".format(pseudo, nomfich)

except IOError:
    self.redirect("/erreur-im")

and the database code:

user={
    "pseudo": pseudo, 
    "password":password, 
    "email":email, 
    "tel":tel, 
    "commune":commune,    
    "statut":statut, 
    "nom":nom, 
    "prenom":prenom, 
    "daten":daten, 
    "sexe":sexe, 
    "avatar":avatar
}

self.db.essog.insert(user)  

and it worked ok, the "avatar" is saved, but there in no image, it saves only a name!

my problem is:

  • to understand how database deals with pictures, must i make image.save(path, format), but the path, is it a path of a normal system path (windows, or linux)?
  • the profile is simple, and i've limited the picture upload to 500ko, and the document in mongodb is 16mb, so the document will handle the entire profile, but must i use gridFS even for small document when it contains picture? the key problem is in path of the picture saving, am stuck, and it's the first time i deal with database, so am sorry for that question.
jdi
  • 90,542
  • 19
  • 167
  • 203
Abdelouahab Pp
  • 4,252
  • 11
  • 42
  • 65
  • I can't quite follow what you're trying to do. `avatar` looks like a file pathname that I don't see used to actually save the uploaded image and I don't see you trying to save the image bytes as part of a `user` document either. – JohnnyHK Aug 11 '12 at 16:06
  • format your source code properly –  Aug 11 '12 at 17:59
  • @JohnnyHK sorry, because i've uploaded only the fragment of the code sorry for the delay the answer below gave me the explication :D thank you :) – Abdelouahab Pp Aug 11 '12 at 23:29

4 Answers4

18

You don't necessarily need GridFS for storing files in MongoDB, but it surely makes it a nicer experience, because it handles the splitting and saving of the binary data, while making the metadata also available. You can then store an ID in your User document to the avatar picture.

That aside, you could also store binary data directly in your documents, though in your code you are not saving the data. You simply are opening it with PIL.Image, but then doing nothing with it.

Assuming you are using pymongo for your driver, I think what you can do is just wrap the binary data in a Binary container, and then store it. This is untested by me, but I assume it should work:

from pymongo.binary import Binary

binary_avatar = Binary(avat)

user={
    ...
    "avatar":avatar,
    "avatar_file": binary_avatar
    ...
}

Now that being said... just make it easier on yourself and use GridFS. That is what it is meant for.

If you were to use GridFS, it might look like this:

from gridfs import GridFS

avat_ctype = self.request.files['avatar'][0]["content_type"]

fs = GridFS(db)
avatar_id = fs.put(avat, content_type=avat_ctype, filename=nomfich)

user={
    ...
    "avatar_name":avatar,
    "avatar_id": avatar_id
    ...
}
jdi
  • 90,542
  • 19
  • 167
  • 203
  • wow! that's what i search! because the profile will use the simple document, but the user uploads will use gridFS and i'll add the key to make some "join" between them. thank you again and to retrieve data, i guess i'll use the binary_avatar variable! thank you! – Abdelouahab Pp Aug 11 '12 at 23:28
  • 1
    Yes to retrieve again you just do a "get" with that ID that will be stored in the user profile as "avatar_id" – jdi Aug 12 '12 at 05:08
  • 2
    hi i've tried the code and it worked, dont know if it's a typo, but it's from bson.binary and not pymongo.binary and the get, will work for both gridfs and binary? – Abdelouahab Pp Aug 12 '12 at 13:35
  • 1
    Pymongo uses bson so its from the bson module either way. And no it would be completely different if you used the Binary approach and put it directly in the user doc. It would just be a binary blob in the doc. There is no specific id for it. Gridfs will give you an ID for it as a reference to use in your user doc. – jdi Aug 12 '12 at 15:24
  • so, from what i understand, PIL is only for control or resizing images, and it's not hime who will save to the database, so if i make a thumbnail, where to save the image? or do i save it directly using GridFS, because am stucked making difference between filesystem path, and database path. – Abdelouahab Pp Aug 12 '12 at 16:42
  • and last question (sorry for disturbing): when i'll show it in the html file, how do i call that file? do it manage its own system of files (and use tornado template) – Abdelouahab Pp Aug 12 '12 at 16:44
  • 1
    You need PIL for doing conversions, such as making your thumbnails. Those new thumbnails would also have to be stored in GridFS. For one of my sites, I store the main image, and then add that ID as a parent id in the gridfs metadata of the thumbnails. There is no system filepath because you are using a different storage mechanism. For serving them, you can make a simple view that serves the image from an ID. For production, I use the gridfs plugin for nginx, to have them served directly. Then it doesnt go through django. The django view is just for dev. – jdi Aug 12 '12 at 17:52
  • now i get the code more clear! i'll try to convert what you said to code, because am not good on it :D thank you again :) – Abdelouahab Pp Aug 12 '12 at 23:56
15

This is the code to insert and retrieve image in mongodb without using gridfs.

def insert_image(request):
    with open(request.GET["image_name"], "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read())
    print encoded_string
    abc=db.database_name.insert({"image":encoded_string})
    return HttpResponse("inserted")

def retrieve_image(request):
    data = db.database_name.find()
    data1 = json.loads(dumps(data))
    img = data1[0]
    img1 = img['image']
    decode=img1.decode()
    img_tag = '<img alt="sample" src="data:image/png;base64,{0}">'.format(decode)
    return HttpResponse(img_tag)
KyungHoon Kim
  • 2,859
  • 2
  • 23
  • 26
Shiva
  • 988
  • 4
  • 15
  • 31
  • in this example, is `request.GET["image_name"]` a string containing the path to a file on the file system? if so, what about the step of uploading the image? I'd like to have an upload mechanism that inserts directly into mongodb, handling the upload in memory and never writing a file to disk. – Kasapo Jul 11 '19 at 18:48
  • ok, i figured it out; but also is there a reason you `dumps` and `loads` the data and then decode it again? I find I can simply use `data = db.collection.find(); imgdata = data[0]['image']; imgtype = data[0]['type'];` (i saved the content_type) and then return `HttpResponse(''.format(imgtype, imgdata` and no need to decode again. Just curious if there's a reason for dumps/loads/decode in the `retrieve_image` fn – Kasapo Jul 11 '19 at 19:25
4

there is an error in :

          from pymongo.binary import Binary

the correct syntax is:

          from bson.binary import Binary

thk you all for your endless support

Luca

barzotto
  • 49
  • 2
0

You need to save binary data using the Binary() datatype of pymongo.

http://api.mongodb.org/python/2.0/api/bson/binary.html#module-bson.binary