pedrodinism
pedrodinism

Reputation: 35

Save uploaded image to database on Flask

I'm learning Python and using Flask to develop an application and one of the features is that a user can upload a profile picture and that image should be saved in the database.

I have a form where the user can upload a file, like this:

<form action="/myprofile" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <input class="form-control" name="picture" placeholder="Picture" type="file">
    </div>
    <button class="btn btn-primary" type="submit">Submit</button>
</form>

And then, in the application.py file I'm handling it like this:

@app.route("/myprofile", methods=["GET", "POST"])
@login_required
def myprofile():
    if request.method == "POST":
        
        db.execute("UPDATE users SET role = :role, picture = :picture, linkedin = :linkedin WHERE id = :user_id", role = request.form.get("role"), picture = request.files("picture"), linkedin = request.form.get("linkedin"), user_id = session["user_id"])

        return render_template("home.html")
    else:
        return render_template("myprofile.html")

This is returning an Internal Server Error. Does anyone have any idea why?

Thanks for your time!

Upvotes: 2

Views: 15579

Answers (1)

Federico Ba&#249;
Federico Ba&#249;

Reputation: 7656

I don't see what error you get, however I want to share one of my previous answer regarding uploading an image into Flask. 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


Some Code from my Github Repo


Initiate the database, configs and Picture table for the databse

In class FileContent(db.Model):

  • data = file.read() It saves in database the Binary version of thefile -render_file = render_picture(data). It saves the decode version, so that you can you see it for render it in the webpages.

      # 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}'
    

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

So here is what is going on in the app route:

  • def render_picture(data) --> Takes the bites raw version of the pic and return the decode version, so that it can be used to be display on the web.

  • data = file.read() : This is the raw data.This can be used for downloading the pic from database

  • render_file: decoded file so you can retrieve it and the render in the web page

    #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
    
    
    @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')
    

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>

Upvotes: 7

Related Questions