Skip to main content

Library that works with Flask & SqlAlchemy to store files in your database and server.

Project description

Build Status Codacy Badge codecov Documentation Status PyPI version PyPI - Python Version PyPI - License

FlaskFileUpload

Library that works with Flask & SqlAlchemy to store files on your server & in your database

Read the docs: Documentation

Installation

Please install the latest stable release:

pip install flask-file-upload

Flask File Upload

General Flask config options

(Important: The below configuration variables need to be set before initiating FileUpload)

    # This is the directory that flask-file-upload saves files to. Make sure the UPLOAD_FOLDER is the same as Flasks's static_folder or a child. For example:
    app.config["UPLOAD_FOLDER"] = join(dirname(realpath(__file__)), "static/uploads")
    
    # Other FLASK config varaibles ...
    app.config["ALLOWED_EXTENSIONS"] = ["jpg", "png", "mov", "mp4", "mpg"]
    app.config["MAX_CONTENT_LENGTH"] = 1000 * 1024 * 1024  # 1000mb
    app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://localhost:5432/blog_db"

Setup

We can either pass the instance to FileUpload(app) or to the init_app(app) method:

app = Flask(__name__, static_folder="static") # IMPORTANT: This is your root directory for serving ALL static content!

db = SQLAlchemy()

file_upload = FileUpload()

# An example using the Flask factory pattern
def create_app():
    db.init_app(app) 
    # Pass the Flask app instance as the 1st arg &
    # the SQLAlchemy object as the 2nd arg to file_upload.init_app.
    file_upload.init_app(app, db)

# Or we can pass the Flask app instance directly & the Flask-SQLAlchemy instance:
db = SQLAlchemy(app)
# Pass the Flask app instance as the 1st arg &
# the SQLAlchemy object as the 2nd arg to FileUpload
file_upload = FileUpload(app, db)
app: Flask = None

Decorate your SqlAlchemy models

Flask-File-Upload (FFU) setup requires each SqlAlchemy model that wants to use FFU library to be decorated with @file_upload.Model .This will enable FFU to update your database with the extra columns required to store files in your database. Declare your attributes as normal but assign a value of file_upload.Column. This is easy if you are using Flask-SqlAlchemy:

from flask_sqlalchemy import SqlAlchemy

db = SqlAlchemy()

Full example:

from my_app import file_upload

@file_upload.Model
class blogModel(db.Model):
   __tablename__ = "blogs"
   id = db.Column(db.Integer, primary_key=True)

   # Use flask-file-upload's `file_upload.Column()` to associate a file with a SQLAlchemy Model:
   my_placeholder = file_upload.Column()
   my_video = file_upload.Column()

define files to be uploaded:

    # A common scenario could be a video with placeholder image.
    # So first lets grab the files from Flask's request object:
    my_video = request.files["my_video"]
    placeholder_img = request.files["placeholder_img"]

Save files

Now we have the files assigned to variables, we can start using the m with flask-file-upload:

    file_upload.save_files(blog_post, files={
        "my_video": my_video,
        "placeholder_img": placeholder_img,
    })
If you followed the setup above you will see the following structure saved to your app:

FlaskFileUpload

Update files

    blog_post = file_upload.update_files(blog_post, files={
        "my_video": new_my_video,
        "placeholder_img": new_placeholder_img,
    })

Delete files

Deleting files from the db & server can be non trivial, especially to keep both in sync. The file_upload.delete_files method can be called with a kwarg of clean_up & then depending of the string value passed it will provide 2 types of clean up functionality:

  • files will clean up files on the server but not update the model
  • model will update the model but not attempt to remove the files from the server. See delete_files Docs for more details
    # Example using a SqlAlchemy model with an appended
    # method that fetches a single `blog`
    blogModel = BlogModel()
    blog_results = blogModel.get_one()
    
    # We pass the blog & files
    blog = file_upload.delete_files(blog_result, files=["my_video"])
    
    # If parent kwarg is set to True then the root primary directory & all its contents will be removed.
    # The model will also get cleaned up by default unless set to `False`.
    blog_result = file_upload.delete_files(blog_result, parent=True, files=["my_video"])


    # If the kwarg `commit` is not set or set to True then the updates are persisted.
    # to the session. And therefore the session has been commited.
    blog = file_upload.delete_files(blog_result, files=["my_video"])
    
    # Example of cleaning up files but not updating the model:
    blog = file_upload.delete_files(blog_result, files=["my_video"], clean_up="files")

Stream a file

    file_upload.stream_file(blog_post, filename="my_video")

File Url paths

    file_upload.get_file_url(blog_post, filename="placeholder_img")

Example for getting file urls from many objects:

    # If blogs_model are many blogs:
    for blog in blog_models:
        blog_image_url = file_upload.get_file_url(blog, filename="blog_image")
        setattr(blog, "blog_image", blog_image_url)

Set file paths to multiple objects - Available in 0.1.0-rc.6 & v0.1.0

The majority of requests will require many entities to be returned & these entities may have SQLAlchemy backrefs with relationships that may also contain Flask-File-Upload (FFU) modified SQLAlchemy models. To make this trivial, this method will set the appropriate filename urls to your SQLAlchemy model objects (if the transaction hasn't completed then add_file_urls_to_models will complete the transaction by default).

The first argument required by this method is models - the SQLAlchemy model(s).

Then pass in the required kwarg filenames which references the parent's FFU Model values - this is the file_upload.Model decorated SQLALchemy model

  • file_upload.Column() method.

Important! Also take note that each attribute set by this method postfixes a _url tag. e.g blog_image becomes blog_image_url

Example for many SQLAlchemy entity objects (or rows in your table)::

    @file_upload.Model
    class BlogModel(db.Model):

        blog_image = file_upload.Column()

Now we can use the file_upload.add_file_urls_to_models to add file urls to each SQLAlchemy object. For example::

    blogs = add_file_urls_to_models(blogs, filenames="blog_image")

    # Notice that we can get the file path `blog_image` + `_url`
    assert  blogs[0].blog_image_url == "path/to/blogs/1/blog_image_url.png"

To set filename attributes to multiple SQLAlchemy parent models with backrefs to multiple child SQLAlchemy models, we can assign to the optional backref kwarg the name of the backref model & a list of the file attributes we set with the FFU Model decorated SQLAlchemy model.

To use backrefs we need to declare a kwarg of backref & pass 2 keys: - name: The name of the backref relation - filenames: The FFU attribute values assigned to the backref model

For example::

    # Parent model
    @file_upload.Model
    class BlogModel(db.Model):
        # The backref:
        blog_news = db.relationship("BlogNewsModel", backref="blogs")
        blog_image = file_upload.Column()
        blog_video = file_upload.Column()

    # Model that has a foreign key back up to `BlogModel
    @file_upload.Model
    class BlogNewsModel(db.Model):
        # The foreign key assigned to this model:
        blog_id = db.Column(db.Integer, db.ForeignKey("blogs.blog_id"))
        news_image = file_upload.Column()
        news_video = file_upload.Column()

The kwarg backref keys represent the backref model or entity (in the above example this would be the BlogNewsModel which we have named blog_news. Example::

    blogs = add_file_urls_to_models(blogs, filenames=["blog_image, blog_video"],
        backref={
            "name": "blog_news",`
            "filenames": ["news_image", "news_video],
    })

WARNING: You must not set the relationship kwarg: lazy="dynamic"! If backref is set to "dynamic" then back-referenced entity's filenames will not get set. Example::

    # This will work
    blog_news = db.relationship("BlogNewsModel", backref="blog")

    # this will NOT set filenames on your model class
    blog_news = db.relationship("BlogNewsModel", backref="blog", lazy="dynamic")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flask-file-upload-0.1.3.tar.gz (16.6 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page