• Stars
    star
    153
  • Rank 241,840 (Top 5 %)
  • Language
    Python
  • License
    MIT License
  • Created almost 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easy file uploads for Flask.

Upload Python Package Python application Documentation Status PyPI version PyPI - Python Version FlaskFileUpload

Library that works with Flask (version 1 or 2) and SqlAlchemy to store files on your server & in your database

Read the docs: Documentation

Installation

Please install the latest release:

pip install flask-file-upload

If you are updating from >=0.1 then please read the upgrading instruction

General Flask config options

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

from flask_file_upload.file_upload import FileUpload
from os.path import join, dirname, realpath

# 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:

from flask_file_upload import FileUpload


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)
    
    # If you require importing your SQLAlchemy models then make sure you import
    # your models after calling `file_upload.init_app(app, db)` or `FileUpload(app, db)`. 
    from .model import * 

# 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

To add files to your model, pass a dict of keys that reference the attribute name(s) defined in your SqlAlchemy model & values that are your files. For Example:

file_upload.add_files(blog_post, files={
    "my_video": my_video,
    "placeholder_img": placeholder_img,
})

# Now commit the changes to your db
db.session.add(blog_post)
db.session.commit()

It's always good practise to commit the changes to your db as close to the end of your view handlers as possible (we encourage you to use add_files over the save_files method for this reason).

If you wish to let flask-file-upload handle adding & committing to the current session then use file_upload.save_files - this method is only recommended if you are sure nothing else needs committing after you have added you files. For example:

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 a a single or 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")

Running Flask-Migration After including Flask-File-Upload in your project

The arguments below will also run if you're using vanilla Alembic.

export FLASK_APP=flask_app.py # Path to your Flask app

# with pip
flask db stamp head
flask db migrate
flask db upgrade

# with pipenv
pipenv run flask db stamp head
pipenv run flask db migrate
pipenv run flask db upgrade

Upgrading from v0.1 to v0.2

You will need to create a migration script with the below column name changes:

  • [you_file_name]__file_type becomes [you_file_name]__mime_type
  • [you_file_name]__mime_type becomes [you_file_name]__ext
  • [you_file_name]__file_name stays the same

More Repositories

1

pytask-io

Python Async Task Queue
Python
91
star
2

flask-jwt-router

Flask JWT Router is a Python library that adds authorised routes to a Flask app.
Python
54
star
3

pymail-io

An Asynchronous mail server - fire & forget!
Python
28
star
4

react-google-oauth2.0

React frontend login with OAuth 2.0 & integrates a Rest API backend.
TypeScript
21
star
5

react-bare-forms

A bare minimal React form library for quick & simple forms.
TypeScript
20
star
6

bobtail

A little Python WSGI http framework
Python
17
star
7

zx80-dev-tools

ZX Spectrum NEXT development tools for MacOS
Makefile
12
star
8

form-validator

Validate the incoming request's form values & cast to valid Go type
Go
10
star
9

gomek

A tiny http framework
Go
8
star
10

process-runner

Runs many processes
Go
8
star
11

gorilla-controllers

Use controllers with the Gorilla Mux library
Go
7
star
12

password-mixin

Small Python library that adds password hashing methods to ORM objects
Python
6
star
13

cython-starter-template

Starter template to create Python bindings from a C static library
Makefile
5
star
14

jetbrains-killer

C programme that quits any Jetbrains IDE's
C
5
star
15

mongo-id-marshaller

Small Python library to marshal mongo ObjectId's
Python
5
star
16

status-writer

Utility pkg that helps get the status code from the response writer
Go
5
star
17

electron-scaffolder

CLI tool creates a Typescript & React Electron starter template
C
5
star
18

forestmq

Message queue 🌲
C
5
star
19

entity-file-uploader

Handles file uploads & organises files based on your database entities.
Go
4
star
20

env-conf

Grabs environmental variables & maps them to your config type via struct tags
Go
4
star
21

adt-tools

A set of abstract data types
C
4
star
22

multipart-requests

Http multipart form data requests
Go
4
star
23

geolocations-api

Town / City geolocations with FastAPI & Mongo
Python
4
star
24

mandarin

Template engine for Python
Python
3
star
25

locksmith

Identity server 🔐 with admin console
Go
3
star
26

bobtail-upload

File uploads for Bobtail
Python
3
star
27

butter

Merge Go structs
Go
3
star
28

birman

Multipart formdata decoder
Python
3
star
29

slack-messages

Slack messages made easy. Send slack messages to channels from you backend api etc.
Python
3
star
30

identity-client

Agnostic identity client
Go
3
star
31

lists

A linked list static library written in C
C
3
star
32

stacks

A stack structure static library written in C with a few extra features
C
3
star
33

screenshot-cleaner

MacOS command line tool that easily removes screenshots from a directory
Go
2
star
34

socket-watcher

Lists all established network connections
Kotlin
2
star
35

bobtail-cors

Cors for Bobtail
Python
2
star
36

bobtail-logger

Logging middleware for Bobtail
Python
2
star
37

study-manager

MacOS desktop app to organise & schedule your studying
Swift
2
star
38

pg-conf

Sets Postgres environment variables to a config type
Go
2
star
39

route-parser

URL path matcher
C
2
star
40

ticket-manager

Manage tickets
C++
1
star
41

ShootingGallery

C#
1
star
42

squirrel

Simple Python micro web framework written in C
C
1
star
43

sniffy

Sniffs REST & Web apps
Java
1
star
44

cool-todos

Linux desktop app that manages your daily todos
C
1
star
45

pycharm-mandarin-plugin

Pycharm plugin for the Mandarin templating engine
1
star
46

pong

Pong for ZX Spectrum NEXT
Assembly
1
star
47

vtk-io-example

C++
1
star
48

sdl2-starter-template

SDL2 Starter Template for C
C
1
star
49

decetralized-insights

Go
1
star
50

webgl-timelines

Display timelines in the DOM
Rust
1
star
51

Spaceship

C#
1
star
52

vscode-c-settings

Starter template to build & run c code in Visual Studio Code
C
1
star
53

z80-assembly-playground

Fun with Z80 Assembly
Assembly
1
star