pythonmongodbflaskgridfs

retrieving files in GridFS to be sent from Flask?


This code is currently working for a file upload from a flask app. The user gives me an integer and a file. I then store the file in GridFS. Now if anyone goes to try to get to the file then gridfs needs to give it back to them if they know the specific integer. We get this when they go to URL/uploads/

Inside of the /uploads/<spacenum> we get the number and call readfile() which will write the desired file to the uploads/ folder. But how can we then take that file and send it? Am I doing this correctly? Presumably I'll need to remove the file from disk afterwards. But I don't have a file object to to send or to unlink like i can when in the upload() function.

I also have another question. I want mongodb to remove these entries about 10 minutes after I've stored them, how can I do this. I understand that I'm supposed to give a special field to gridfs I just don't know exactly how.

app.config['UPLOAD_FOLDER'] = 'uploads/'
db = "spaceshare"
def get_db(): # get a connection to the db above
    conn = None
    try:
        conn = pymongo.MongoClient()
    except pymongo.errors.ConnectionFailure, e:
       print "Could not connect to MongoDB: %s" % e
       sys.exit(1)
    return conn[db]

# put files in mongodb
def put_file(file_name, room_number):
    db_conn = get_db()
    gfs = gridfs.GridFS(db_conn)
    with open('uploads/' + file_name, "r") as f:
        gfs.put(f, room=room_number)

# read files from mongodb
def read_file(output_location, room_number):
    db_conn = get_db()
    gfs = gridfs.GridFS(db_conn)
    _id = db_conn.fs.files.find_one(dict(room=room_number))['_id']
    #return gfs.get(_id).read()
    with open(output_location, 'w') as f:
        f.write(gfs.get(_id).read())

@app.route('/')
def home():
    return render_template('index.html')


@app.route('/upload',methods=['POST'])
def upload():
    #get the name of the uploaded file
    file=request.files['file']
    #print "requested files"
    space=request.form['space']
    # if the file exists make it secure
    if file and space: #if the file exists
        #make the file same, remove unssopurted chars
        filename=secure_filename(file.filename)
        #move the file to our uploads folder
        file.save(os.path.join(app.config['UPLOAD_FOLDER'],filename))
        put_file(filename,space)
        # remove the file from disk as we don't need it anymore after database insert.
        os.unlink(os.path.join( app.config['UPLOAD_FOLDER'] , filename))
        # debugging line to write a file
        f = open('debug.txt', 'w')
        f.write('File name is '+filename+' or ' +file.name+' the space is :'+ str(space) )
        return render_template('index.html', filename = filename ,space = space) ##take the file name
    else:
        return render_template('invalid.html')

@app.route('/uploads/<spacenum>', methods=['GET'])
def return_file(spacenum):
    read_file(app.config['UPLOAD_FOLDER'] ,spacenum)
    send_from_directory(app.config['UPLOAD_FOLDER'], filename)
    return render_template('thanks.html' , spacenum = spacenum)

Here are the sources I've used and the examples I've built this code off of as well as my full source code. Thanks in advance for all your help!

  1. https://github.com/DavidAwad/SpaceShare
  2. http://runnable.com/UiPcaBXaxGNYAAAL/how-to-upload-a-file-to-the-server-in-flask-for-python
  3. https://api.mongodb.org/python/current/examples/gridfs.html

Solution

  • Apparently the problem i was having had to do with file paths. Anyway here is the solution to that problem. Using the String representations as the filenames.

    # read files from mongodb
    def read_file(output_location, room_number):
        db_conn = get_db()
        gfs = gridfs.GridFS(db_conn)
        _id = db_conn.fs.files.find_one(dict(room=room_number))['_id']
        with open(output_location + str(room_number) , 'w') as f:
            f.write(gfs.get(_id).read())
        return gfs.get(_id).read()
    
    
    @app.route('/upload/<spacenum>', methods=['GET'])
    def download(spacenum):
        unSecurefilename = read_file(app.config['UPLOAD_FOLDER'] ,spacenum)
        return send_from_directory(app.config['UPLOAD_FOLDER'], str(spacenum)  )
        #return render_template('index.html' , spacenum = spacenum)