Example Flask application illustrating some of my common practices

Related tags

Flask overholt
Overview

Overholt

Overholt is an example Flask application illustrating some of my common practices

Development Environment

At the bare minimum you'll need the following for your development environment:

  1. Python
  2. MySQL
  3. Redis

It is strongly recommended to also install and use the following tools:

  1. virtualenv
  2. virtualenvwrapper
  3. Vagrant
  4. Berkshelf

Local Setup

The following assumes you have all of the recommended tools listed above installed.

1. Clone the project:

$ git clone [email protected]:mattupstate/overholt.git
$ cd overholt

2. Create and initialize virtualenv for the project:

$ mkvirtualenv overholt
$ pip install -r requirements.txt

3. Install the required cookbooks:

$ berks install

4. Install the Berkshelf plugin for Vagrant:

$ vagrant plugin install vagrant-berkshelf

5. Start virtual machine:

$ vagrant up

6. Upgrade the database:

$ alembic upgrade head

7. Run the development server:

$ python wsgi.py

8. In another console run the Celery app:

$ celery -A overholt.tasks worker

9. Open http://localhost:5000

Development

If all went well in the setup above you will be ready to start hacking away on the application.

Database Migrations

This application uses Alembic for database migrations and schema management. Changes or additions to the application data models will require the database be updated with the new tables and fields. Additionally, ensure that any new models are imported into the consolidated models file at overholt.models. To generate a migration file based on the current set of models run the following command:

$ alembic revision --autogenerate -m "<a description of what was modified>"

Review the resulting version file located in the alembic/versions folder. If the file is to your liking upgrade the database with the following command:

$ alembic upgrade head

For anything beyond this workflow please read the Alembic documentation.

Management Commands

Management commands can be listed with the following command:

$ python manage.py

These can sometimes be useful to manipulate data while debugging in the browser.

Tests

To run the tests use the following command:

$ nosetests
Comments
  • A question for core.Service

    A question for core.Service

    I got a quick question for core.Service. So what's the point to wrap sqlalchemy's methods into Service rather than call them directly in each application?

    Also I didn't find a way to use some sqlalchemy's methods like (query.filter, concatenating multiple filter_by etc.) without calling directly model.query blabla. It seems that Service doesn't provide all methods of sqlalchemy.

    opened by FindBoat 7
  • create_app twice?

    create_app twice?

    Hey, this is an issue I've been running into myself and trying to research it a bit I ran into your pretty nice base project!

    to be able to give functions the annotation @celery.task we need to be able to import the celery = Celery() instance from somewhere.
    but to tie it together with all the Flask related stuff we want to be in app context (and I want to use the config from my app for some celery stuff too) so we need an instance of the app.
    so you create that instance when creating the Celery instance ( I do the same in my project ).

    but this results in doing more create_app calls (or at least 1 more) when importing tasks to queue them from your blueprints.
    The thing is .. I'm not sure if it matters ... but it feels wrong ...

    Just putting it here to discuss, hope you don't mind

    opened by rubensayshi 5
  • Many to many bidirectional relationship is not JSON serializable

    Many to many bidirectional relationship is not JSON serializable

    When I try to access a model with a bidirectional many to many relationship, I get the error: TypeError: <sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x2a01b50> is not JSON serializable The error makes sense, as rv = {..., 'users': <sqlalchemy.orm.dynamic.AppenderBaseQuery object at 0x2758b50>}.

    How would I go about executing that query so it becomes serialized?

    • Do I create a __json_modifiers__ for 'users' and run a lambda to convert it to a list/json?
    • Am I missing something in sqlalchemy that can resolve this?
    projects_users = db.Table('projects_users',
        db.Column('id', db.Integer, primary_key=True),
        db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
        db.Column('project_id', db.Integer, db.ForeignKey('projects.id'))
    )
    
    class UserJsonSerializer(JsonSerializer):
        pass
    
    class User(UserJsonSerializer, UserMixin, db.Model):
        __tablename__ = 'users'
    
        id = db.Column(db.Integer, primary_key=True)
        projects = db.relationship('Project', secondary=projects_users,
            backref=db.backref('users', lazy='dynamic'))
    
    class ProjectJsonSerializer(JsonSerializer):
        # __json_hidden__ = ['users']
        #  __json_modifiers__  = {
        #    'users': lambda x, self: x.all()
        # }
        pass
    
    class Project(ProjectJsonSerializer, db.Model):
        __tablename__ = 'projects'
    
        id = db.Column(db.Integer(), primary_key=True)
        name = db.Column(db.String(255))
    

    Thanks so much for your flask skeleton project. It has cleared up so many questions I had about how to scale large projects.

    opened by scottwernervt 5
  • Service Objects vs Service Mixins

    Service Objects vs Service Mixins

    I'm wondering what are the drawbacks of using mixins vs using objects. I actually implemented services by using a mixin instead of a separate object on its own.

    This helps me in a two ways:

    1. I don't have to define model, since I'm using classmethods to obtain the model I'm running the query on.
    2. I don't have to create or instantiate objects to use getters like all, find, etc.
    class ServiceMixin(object):
    
        def save(self):
            db.session.add(self)
            db.session.commit()
            return self
    
        @classmethod
        def all(cls):
            return cls.query.all()
    
        @classmethod
        def get(cls, _id):
            return cls.query.get(_id)
    
        @classmethod
        def get_all(cls, id_cl="id", *ids):
            id_column = cls.get(id_cl)
            return cls.query.filter(id_column.in_(ids)).all()
    
        @classmethod
        def find(cls, **kwargs):
            return cls.query.filter_by(**kwargs)
    
        @classmethod
        def first(cls, **kwargs):
            return cls.find(**kwargs).first()
    
        @classmethod
        def get_or_404(cls, id):
            return cls.query.get_or_404(id)
    
        @classmethod
        def new(cls, **kwargs):
            return cls(**cls._preprocess_params(kwargs))
    
        @staticmethod
        def _preprocess_params(kwargs):
            kwargs.pop('csrf_token', None)
            return kwargs
    
        @classmethod
        def create(cls, **kwargs):
            return cls.save(cls.new(**kwargs))
    
        def update(self, **kwargs):
            for k, v in self._preprocess_params(kwargs).items():
                setattr(self, k, v)
            self.save()
            return self
    
        def delete(self):
            db.session.delete(self)
            db.session.commit()
    

    To use it, simply inherit it when creating your models:

    class Product(db.Model, ServiceMixin):
        id = db.Column(db.Integer(), primary_key=True)
        name = db.Column(db.String(250))
        ...
    
    Product.all() # Gets all of the products
    Product.find(name="tacos") # Finds all products named "tacos"
    p = Product(name="spegahetti")
    p.save() # Saves the newly created Product
    

    Anyway, this project template is great stuff! Thanks for letting us in on this.

    opened by yiumingh 4
  • Create Overholt without JavaScript

    Create Overholt without JavaScript

    It would be really helpful if there was a version of this repository without the JavaScript. Perhaps just a static version to better show how Flask would work with more projects.

    opened by sethmoon 4
  • Outdated dependencies in requirements.txt

    Outdated dependencies in requirements.txt

    I tried to launch your example, but found out, that there is no such version for kombu. I tried to remove all version specifications, and found out, that you are using deprecated (and removed in current stable version) factory-boy method set_creation_function(). One more error is in WTForms usage.

    Possible fix could be:

    diff --git a/overholt/products/forms.py b/overholt/products/forms.py
    index 2e7adbf..106d72c 100644
    --- a/overholt/products/forms.py
    +++ b/overholt/products/forms.py
    @@ -6,8 +6,7 @@
         Product forms
     """
    
    -from flask_wtf import Form, TextField, SelectMultipleField, Required, \
    -    Optional
    +from wtforms import Form, TextField, SelectMultipleField, validators
    
     from ..services import products
    
    @@ -22,12 +21,12 @@ class ProductFormMixin(object):
    
    
     class NewProductForm(ProductFormMixin, Form):
    -    name = TextField('Name', validators=[Required()])
    +    name = TextField('Name', validators=[validators.Required()])
         categories = SelectMultipleField(
    -        'Categories', coerce=int, validators=[Required()])
    +        'Categories', coerce=int, validators=[validators.Required()])
    
    
     class UpdateProductForm(ProductFormMixin, Form):
    -    name = TextField('Name', validators=[Optional()])
    +    name = TextField('Name', validators=[validators.Optional()])
         categories = SelectMultipleField(
    -        'Categories', coerce=int, validators=[Optional()])
    +        'Categories', coerce=int, validators=[validators.Optional()])
    diff --git a/overholt/stores/forms.py b/overholt/stores/forms.py
    index 4edf74c..5899bae 100644
    --- a/overholt/stores/forms.py
    +++ b/overholt/stores/forms.py
    @@ -6,22 +6,22 @@
         Store forms
     """
    
    -from flask_wtf import Form, TextField, Required, Optional
    +from wtforms import Form, TextField, validators
    
     __all__ = ['NewStoreForm', 'UpdateStoreForm']
    
    
     class NewStoreForm(Form):
    -    name = TextField('Name', validators=[Required()])
    -    address = TextField('Address', validators=[Required()])
    -    city = TextField('City', validators=[Required()])
    -    state = TextField('State', validators=[Required()])
    -    zip_code = TextField('Zip Code', validators=[Required()])
    +    name = TextField('Name', validators=[validators.Required()])
    +    address = TextField('Address', validators=[validators.Required()])
    +    city = TextField('City', validators=[validators.Required()])
    +    state = TextField('State', validators=[validators.Required()])
    +    zip_code = TextField('Zip Code', validators=[validators.Required()])
    
    
     class UpdateStoreForm(Form):
    -    name = TextField('Name', validators=[Optional()])
    -    address = TextField('Address', validators=[Optional()])
    -    city = TextField('City', validators=[Optional()])
    -    state = TextField('State', validators=[Optional()])
    -    zip_code = TextField('Zip Code', validators=[Optional()])
    +    name = TextField('Name', validators=[validators.Optional()])
    +    address = TextField('Address', validators=[validators.Optional()])
    +    city = TextField('City', validators=[validators.Optional()])
    +    state = TextField('State', validators=[validators.Optional()])
    +    zip_code = TextField('Zip Code', validators=[validators.Optional()])
    diff --git a/tests/factories.py b/tests/factories.py
    index 9ebdcb9..63539d2 100644
    --- a/tests/factories.py
    +++ b/tests/factories.py
    @@ -15,22 +15,22 @@ from overholt.core import db
     from overholt.models import *
    
    
    -def create_sqlalchemy_model_function(class_to_create, *args, **kwargs):
    -    entity = class_to_create(**kwargs)
    -    db.session.add(entity)
    -    db.session.commit()
    -    return entity
    +class MyFactory(Factory):
    +    @classmethod
    +    def _create(cls, target_class, *args, **kwargs):
    +        entity = target_class(**kwargs)
    +        db.session.add(entity)
    +        db.session.commit()
    +        return entity
    
    -Factory.set_creation_function(create_sqlalchemy_model_function)
    
    -
    -class RoleFactory(Factory):
    +class RoleFactory(MyFactory):
         FACTORY_FOR = Role
         name = 'admin'
         description = 'Administrator'
    
    
    -class UserFactory(Factory):
    +class UserFactory(MyFactory):
         FACTORY_FOR = User
         email = Sequence(lambda n: 'user{0}@overholt.com'.format(n))
         password = LazyAttribute(lambda a: encrypt_password('password'))
    @@ -43,7 +43,7 @@ class UserFactory(Factory):
         active = True
    
    
    -class StoreFactory(Factory):
    +class StoreFactory(MyFactory):
         FACTORY_FOR = Store
         name = Sequence(lambda n: 'Store Number {0}'.format(n))
         address = '123 Overholt Alley'
    @@ -52,11 +52,11 @@ class StoreFactory(Factory):
         zip_code = '12345'
    
    
    -class ProductFactory(Factory):
    +class ProductFactory(MyFactory):
         FACTORY_FOR = Product
         name = Sequence(lambda n: 'Product Number {0}'.format(n))
    
    
    -class CategoryFactory(Factory):
    +class CategoryFactory(MyFactory):
         FACTORY_FOR = Category
         name = Sequence(lambda n: 'Category {0}'.format(n))
    
    opened by peterdemin 3
  • Error running 'alembic upgrade head'

    Error running 'alembic upgrade head'

    Using Python 2.7 after a fresh install I get the following error. I've dug around in the source for hours and traced it to something to do with overholt/tasks.py but I don't know how to fix it properly.

    Any ideas? thanks

    $ alembic upgrade head Traceback (most recent call last): File "/var/www/recruitinginbox.com/venv2.7/bin/alembic", line 8, in load_entry_point('alembic==0.6.4', 'console_scripts', 'alembic')() File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/config.py", line 298, in main CommandLine(prog=prog).main(argv=argv) File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/config.py", line 293, in main self.run_cmd(cfg, options) File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/config.py", line 279, in run_cmd **dict((k, getattr(options, k)) for k in kwarg) File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/command.py", line 125, in upgrade script.run_env() File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/script.py", line 203, in run_env util.load_python_file(self.dir, 'env.py') File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/util.py", line 212, in load_python_file module = load_module_py(module_id, path) File "/var/www/recruitinginbox.com/venv2.7/local/lib/python2.7/site-packages/alembic/compat.py", line 58, in load_module_py mod = imp.load_source(module_id, path, fp) File "alembic/env.py", line 15, in app = create_app() File "/var/www/recruitinginbox.com/overholt/api/init.py", line 23, in create_app register_security_blueprint=register_security_blueprint) File "/var/www/recruitinginbox.com/overholt/factory.py", line 44, in create_app register_blueprints(app, package_name, package_path) File "/var/www/recruitinginbox.com/overholt/helpers.py", line 26, in register_blueprints m = importlib.import_module('%s.%s' % (package_name, name)) File "/usr/lib/python2.7/importlib/init.py", line 37, in import_module import(name) File "/var/www/recruitinginbox.com/overholt/api/stores.py", line 13, in from ..tasks import send_manager_added_email, send_manager_removed_email File "/var/www/recruitinginbox.com/overholt/tasks.py", line 12, in celery = create_celery_app() File "/var/www/recruitinginbox.com/overholt/factory.py", line 52, in create_celery_app app = app or create_app('overholt', os.path.dirname(file)) File "/var/www/recruitinginbox.com/overholt/factory.py", line 44, in create_app register_blueprints(app, package_name, package_path) File "/var/www/recruitinginbox.com/overholt/helpers.py", line 26, in register_blueprints m = importlib.import_module('%s.%s' % (package_name, name)) File "/usr/lib/python2.7/importlib/init.py", line 37, in import_module import(name) ImportError: No module named overholt

    opened by dukedougal 2
  • Basic questions about vagrant

    Basic questions about vagrant

    Hi, Thanks very much for taking the time to write this code and share its analysis! I've not used Vagrant before, and was wondering if you might be able to shed some light on its use within overholt.

    From what I can tell after reading the docs and the Vagrantfile, it looks like the virtual machine only gets used for MySQL/Redis.io backend storage - with the actual flask development server running on the local machine.. Is that correct?

    I suppose I'm just confused what the exact role vagrant plays in the development stack here, and why more of the web server aspects aren't part of the virtual machine?

    Best,

    opened by briancappello 2
  • Upgrading flask-security fails tests

    Upgrading flask-security fails tests

    Upgrading flask-security beyond version 1.6.5 causes the tests to fail. More specifically, login/logout doesn't seem to work. In the dashboard tests, the response always contains the full template, even if the user isn't logged in first, or if the user is logged out at the beginning of the test.

    To reproduce:

    pip install --upgrade Flask-Security==1.6.6
    pip install --upgrade Flask-WTF==0.8
    nosetests
    

    (Second pip line is necessary else Flask-Security does complain about some missing imports. Not sure why pip pulls the wrong dependencies here.)

    Any idea what might have changed between 1.6.5 and 1.6.6 that causes the tests to fail? Or is it really just due to the WTF forms? If yes, I don't understand how this influences _login() of the test module.

    opened by arnuschky 1
  • How to use more then one route on the same view function?

    How to use more then one route on the same view function?

    Currently, a view function only has one route. @route(bp, '/someurl', methods=['GET']). e.g. But how about if I need more then one url mapping for the same view function?

    opened by kinorsi 1
  • Implementing Application Dispatching by Path/Subdomain

    Implementing Application Dispatching by Path/Subdomain

    Hi, I really like the suggested structure of your flas applications... I'm really new to Flask and to the freedom it provides. If you fin the time, can you answer a question?

    I'm creating a multi-tenant application using the PostgreSQL schemas, where I will have a public schema + a schema for each tenant. So, I need my application to be something like this: http://www.application.com/tenant/

    I'm pretty sure the answer to achieve that is something like this: http://flask.pocoo.org/docs/patterns/appdispatch/#dispatch-by-path

    The problem is that I do not know how to best acommodate this in the overholt architecture. Could you give me some tips?

    Thank you very much

    opened by DanielFerreiraJorge 1
  • potential decorator issue

    potential decorator issue

    I think you mean to return wrapper here, instead of return f, right? https://github.com/mattupstate/overholt/blob/master/overholt/api/init.py#L50

    otherwise the bp.route and other decorators won't apply. maybe i'm misunderstanding!

    opened by don-swept 0
  • how to init database

    how to init database

    I had change the url of connecting mysql,and created a database named overholt ,but no tables in it. what I want to konw is that how can create the tables???

    thank you ! @mattupstate

    opened by duckbill 2
  • python3 & update packages to latest

    python3 & update packages to latest

    • Updated test factories to use factory.alchemy.SQLAlchemyModelFactory
    • Added orm scoped session for db connections
    • Updated packages to latest
    • is_authenticated is not callable any more
    • updating to python 3 print()
    • updating wtforms imports. TextField is now StringField and Required is now DataRequired
    • fix for SQLAlchemy error TypeError: unhashable type: 'Role'
    • Added @factory.post_generation hook for roles generation when a user is created
    • Secret key utf8 encoded to match FlaskTestCaseMixin hmacs version

    Updating to latest packages had last been done in #23, which I wish I had checked before updating myself!

    opened by RedCraig 1
  • Flask Principal within Overholt

    Flask Principal within Overholt

    Hey, Can you show how to use flask-principal within this, as in where does the Role get managed, and how to use the protected views. Do you create a new Service object per role that you need? Or just use the Flask-Principal decorators to hide the views?

    opened by tejovanthn 0
  • How to use Flask-Restful with this structure

    How to use Flask-Restful with this structure

    I'm using Flask-Restful for my API but how would I use api.add_resource similar to how you did route?

    Also I want to add some wrappers for app and api. Where is the best place to have these wrappers?

    opened by ghost 1
flask-apispec MIT flask-apispec (🥉24 · ⭐ 520) - Build and document REST APIs with Flask and apispec. MIT

flask-apispec flask-apispec is a lightweight tool for building REST APIs in Flask. flask-apispec uses webargs for request parsing, marshmallow for res

Joshua Carp 617 Dec 30, 2022
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.

Flask-Bcrypt Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application. Due to the recent increased prevelance of

Max Countryman 310 Dec 14, 2022
Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.

Flask-Bcrypt Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application. Due to the recent increased prevelance of

Max Countryman 282 Feb 11, 2021
Flask-Starter is a boilerplate starter template designed to help you quickstart your Flask web application development.

Flask-Starter Flask-Starter is a boilerplate starter template designed to help you quickstart your Flask web application development. It has all the r

Kundan Singh 259 Dec 26, 2022
flask-reactize is a boostrap to serve any React JS application via a Python back-end, using Flask as web framework.

flask-reactize Purpose Developing a ReactJS application requires to use nodejs as back end server. What if you want to consume external APIs: how are

Julien Chomarat 4 Jan 11, 2022
A simple example using Flask inside a container

This is a simple example of how create a container for a Python Flask Web Application using Docker.

Fazt Web 8 Aug 30, 2022
An python flask app with webserver example

python-flask-example-keepalive How it works? Basically its just a python flask webserver which can be used to keep any repl/herokuapp or any other ser

KangersHub 2 Sep 28, 2022
a flask profiler which watches endpoint calls and tries to make some analysis.

Flask-profiler version: 1.8 Flask-profiler measures endpoints defined in your flask application; and provides you fine-grained report through a web in

Mustafa Atik 718 Dec 20, 2022
Flask-Rebar combines flask, marshmallow, and swagger for robust REST services.

Flask-Rebar Flask-Rebar combines flask, marshmallow, and swagger for robust REST services. Features Request and Response Validation - Flask-Rebar reli

PlanGrid 223 Dec 19, 2022
Brandnew-flask is a CLI tool used to generate a powerful and mordern flask-app that supports the production environment.

Brandnew-flask is still in the initial stage and needs to be updated and improved continuously. Everyone is welcome to maintain and improve this CLI.

brandonye 4 Jul 17, 2022
Flask Project Template A full feature Flask project template.

Flask Project Template A full feature Flask project template. See also Python-Project-Template for a lean, low dependency Python app. HOW TO USE THIS

Bruno Rocha 96 Dec 23, 2022
A Fast API style support for Flask. Gives you MyPy types with the flexibility of flask

Flask-Fastx Flask-Fastx is a Fast API style support for Flask. It Gives you MyPy types with the flexibility of flask. Compatibility Flask-Fastx requir

Tactful.ai 18 Nov 26, 2022
Flask-app scaffold, generate flask restful backend

Flask-app scaffold, generate flask restful backend

jacksmile 1 Nov 24, 2021
Flask pre-setup architecture. This can be used in any flask project for a faster and better project code structure.

Flask pre-setup architecture. This can be used in any flask project for a faster and better project code structure. All the required libraries are already installed easily to use in any big project.

Ajay kumar sharma 5 Jun 14, 2022
Flask-Discord-Bot-Dashboard - A simple discord Bot dashboard created in Flask Python

Flask-Discord-Bot-Dashboard A simple discord Bot dashboard created in Flask Pyth

Ethan 8 Dec 22, 2022
Open-source Flask Sample built on top of flask-dance library

Open-source Flask Sample built on top of flask-dance library. The project implements the social login for Github and Twitter - Originally coded by TestDriven.IO.

App Generator 4 Jul 26, 2022
Flask-redmail - Email sending for Flask

Flask Red Mail: Email Sending for Flask Flask extension for Red Mail What is it?

Mikael Koli 11 Sep 23, 2022
Flask Sitemapper is a small Python 3 package that generates XML sitemaps for Flask applications.

Flask Sitemapper Flask Sitemapper is a small Python 3 package that generates XML sitemaps for Flask applications. This allows you to create a nice and

null 6 Jan 6, 2023
Flask-template - A simple template for make an flask api

flask-template By GaGoU :3 a simple template for make an flask api notes: you ca

GaGoU 2 Feb 17, 2022