-1

I am making a website where users have the ability to submit image files. Under the image files, I would like the user to have the ability to type certain things in the text box (ex. date of photo, location, etc.) and have the image and text from the text form be put into the same file. How is this possible? Currently I am using flask_upload to have the user submit the image into a folder on my computer.

from flask import Flask, render_template, url_for, request
from flask_uploads import UploadSet, configure_uploads, IMAGES

app = Flask(__name__)

photos = UploadSet('photos', IMAGES)
app.config['UPLOADED_PHOTOS_DEST'] = 'photoup'
configure_uploads(app, photos)


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

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST' and 'photo' in request.files:
        filename = photos.save(request.files['photo'])
        return redirect(url_for('description'))
    return render_template('upload.html')
      

if __name__ == "__main__":
    app.run(debug=True)
<html>
<head>
    <title>Upload</title>
</head>
<body>
<form method=POST enctype=multipart/form-data action="{{ url_for('upload') }}">
    <input type=file name=photo>
    <input type="submit">
</form>
</body>
</html>

Zathura
  • 47
  • 5
  • You should also add the code from the app.route of 'descrption, ```return redirect(url_for('description'))``` I don't see this function in the code? – Federico Baù Aug 13 '20 at 04:49
  • What do you mean by ' and have the image and text from the text form be put into the same file' ? I guess like you want to be able to upload a photo and a text, once I retrieve it from a Database I get both back correct? If yes then you need to save them in the same database table but separate from different data type – Federico Baù Aug 13 '20 at 04:53
  • Yeah that's what I would like to do^ – Zathura Aug 13 '20 at 14:32
  • Ok, I have been hangup for this one day. It seems that flask_uploads has some issue(check the answer) so I decided to avoid using it. I have full code in GitHub. – Federico Baù Aug 17 '20 at 04:45

1 Answers1

0

So I Tried to make an example with flask_uploads however it seems there is an issue with it Werkzeug compatibily. It seems that the last version that works is the Werkzeug==0.16.0. I found this in this SO answer:flask_uploads: ImportError: cannot import name 'secure_filename'


EDIT

So Looking but around I also found this GitHub Repo by 'Grey Li' Here

In a comment section they confirm that flask_uploads works only with werkzeug==0.16.1 version.

However one solution is to install Flask-Reuploaded Here. I may try it out and upload my GitHub app with another version of my app using flask_uploads


Have said that, I prepared a mini app that is doing just what you asked for, using flask, flask_sqlalchemy (with sqlite3), html and Bootstrap.

You can find the full code here(I will update it with more secure file uploads) as the one given here is only a small part:

FULL CODE

Long story short, this are the most important part that will answer your question:

## Initiate the database, configs and Picture table for the databse ##

# Built-in Imports
import os
from datetime import datetime
from base64 import b64encode
import base64
from io import BytesIO #Converts data from Database into bytes

# Flask
from flask import Flask, render_template, request, flash, redirect, url_for, send_file # Converst bytes into a file for downloads

# FLask SQLAlchemy, Database
from flask_sqlalchemy import SQLAlchemy


basedir = 'sqlite:///' + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data.sqlite')

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = basedir
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'dev'
db = SQLAlchemy(app)

# Picture table. By default the table name is filecontent
class FileContent(db.Model):

    """ 
    The first time the app runs you need to create the table. In Python
    terminal import db, Then run db.create_all()
    """
    """ ___tablename__ = 'yourchoice' """ # You can override the default table name

    id = db.Column(db.Integer,  primary_key=True)
    name = db.Column(db.String(128), nullable=False)
    data = db.Column(db.LargeBinary, nullable=False) #Actual data, needed for Download
    rendered_data = db.Column(db.Text, nullable=False)#Data to render the pic in browser
    text = db.Column(db.Text)
    location = db.Column(db.String(64))
    pic_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    def __repr__(self):
        return f'Pic Name: {self.name} Data: {self.data} text: {self.text} created on: {self.pic_date} location: {self.location}'

INDEX Route

# Index It routes to index.html where the upload forms is 
@app.route('/index', methods=['GET', 'POST'])
@app.route('/')
def index():

    return render_template('index.html')

INDEX HTML with the Form

<form method="POST" action="/upload" enctype="multipart/form-data">
        <!-- File Upload-->
        <div class="form-group">
            <label for="inputFile">File input</label>
            <input class="form-control-file" type="file" name="inputFile">
        </div>

        <!-- Location -->
        <div class="form-group">
            <label for="location">Location</label>
            <input class="form-control" type="text" name="location">
        </div>

        <!-- Text -->
        <div class="form-group">
            <label for="text">Write Text</label>
            <textarea class="form-control" name="text" id="text" rows="5" placeholder="Add a Description"></textarea>
        </div>

        <!-- Submit -->        
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>

Upload route, here is where the picture its sent to databse and processed with correct data

# Render the pics, this Function converts the data from request.files['inputFile'] so that in can be displayed
def render_picture(data):
    
    render_pic = base64.b64encode(data).decode('ascii') 
    return render_pic

# Upload
@app.route('/upload', methods=['POST'])
def upload():

    file = request.files['inputFile']
    data = file.read()
    render_file = render_picture(data)
    text = request.form['text']
    location = request.form['location']

    newFile = FileContent(name=file.filename, data=data, rendered_data=render_file, text=text, location=location)
    db.session.add(newFile)
    db.session.commit() 
    flash(f'Pic {newFile.name} uploaded Text: {newFile.text} Location: {newFile.location}')
    return render_template('upload.html')
Federico Baù
  • 6,013
  • 5
  • 30
  • 38