This is the second installment of a tutorial series focusing on how to create a full-stack application using Flask and Stream. This week we’re going to start digging into the actual construction of our app. In this article, I am going to guide you through setting up the initial files and structure, as well as registering for Stream and getting you familiar with some of its core concepts to get more familiar with it. Check out the Github repo here to help you follow along!
Getting Started
The first thing we have to do is create a new directory to house our project in. I am going to name mine "offbrand-tutorial", but feel free to name yours whatever you’d like. After that, we are going to boot up a virtual environment(venv). Opening your command-line tool, navigate to the project directory you just created. If you haven’t already, install venv
with pip
.
pip install python3-venv
Next, we are going to initialize the virtual environment in the project:
python3 -m venv venv
This will create a new virtual environment named venv within your project, which helps to keep all of your Python packages together and separated from your local computer to avoid conflicts between libraries. Before we continue, make sure you activate your environment.
(WIth Windows)
venv\Scripts\activate
Back to Basics
When dealing with a project of this scale, the organization is critical. With that in mind, I am going to be using the app factory design and trying my best to keep elements modular to make it easier to add and remove functionality. I am going to start by creating a basic structure that will include features that we will deal with right away, but also a few that will come in handy over the next few articles and tend to be used over and over in your Flask projects.
Pip Install Everything
I typically like to install a handful of Python packages when I start a new project that I know I’ll be using during development. I find this helps in allowing me to write instead of switching back and forth from the terminal to fetch a new library. So, in your command line console:
Pip install stream-python flask-bootstrap flask-sqlalchemy flask-moment
Stream-Python is going to be our workhorse; it will be acting as our data store for the majority of this project, communicating with the Stream API.
Next is Flask-Bootstrap, which brings in Bootstrap to our templates. A word to the wise on this particular library: Bootstrap doesn’t always play well with every Javascript module out there. If you are going to be bringing in third-party JS libraries, you may have to edit the package or leave it out altogether, an understanding that I came to after 16 hours of very frustrating debugging.
After that, flask-sqlalchemy
will be our tool to talk to our sqlite
database, and flask-moment will help convert user-facing timestamps in our application.
Testing the Waters (Pun Fully Intended)
As I mentioned earlier, Stream is going to make up the core of our application. Signing up is a quick process, which you can do either with email or your Github account. We will be creating our feeds as the series progresses and can integrate them one by one into our app. I wanted to take a little bit of time, however, to get you more acquainted with how feeds in Stream work, and how we’ll be integrating them into our app. The first thing to know is that there are three different types of feeds available.
Flat Feeds
Flat feeds are typically your bread and butter. They are activity-based feeds that can be combined with other feeds, through follows, to give you a “timeline”-like view. They work by adding “activities” for an object (like a user or a group/place) to the feed – through which all of the followers of that feed will be able to see in their own. We are going to be using this type extensively for organizing user/collection content.
Aggregated Feeds
Aggregated feeds work in a similar way to flat feeds, but with some critical differences. The first is that they aggregate (makes sense) activity in the feed, like “Johnny and two others watched this video”. The other important part is that Aggregated Feeds cannot be followed. Aggregated feeds provide a rather vital service, though, in that if one of your friends gets bored one day and decides to post 100 times in a row, your feed won’t get hijacked. We will be using this type of feed for our user home page.
Notifications
Unless you’ve lived under a rock for the last ten years, the concept of notifications shouldn’t be entirely new to you (which if you have and still learned modern programming, respect). This particular feed group has some rather handy features, though. First, read counts. Typically, this functionality is pretty write heavy on your database when you implement it yourself, which, once you start hitting any scale is a non-starter if you are trying to keep expenses low. Also, it will give you a convenient count of those unseen/unread notifications.
Second, real-time. You can set up your applications to receive notifications in real-time using Webhooks or AWS SQS, which helps to make your applications more dynamic and user-friendly. The alternative would be to make your users refresh the page every time they want to see new notifications. Notifications also automatically aggregate events like an aggregated feed. We will be using Notifications in the second half of our tutorial when we get into React.
Next Steps
Now that we’ve covered the basics, we’ll launch into creating the main directories and files for our app. When we are finished, you will have an application structure that looks like this:
App-etizer
In the app directory, we’re going to create a few basic files and (yet another) directory. The first file we will be creating is an extensions.py file. This is going to gather together the third party libraries that rely on the app context to function.
app/extensions.py
from flask_bootstrap import Bootstrap from flask_sqlalchemy import SQLAlchemy from flask_moment import Moment bootstrap = Bootstrap() db = SQLAlchemy() moment = Moment()
After that, we will create an init.py
file to initialize (get it?) the app using Flask and register the different blueprints. Don’t stress about the config file or the original plan yet; we will get to those soon.
app/init.py
from flask import Flask from .extensions import bootstrap, db, moment from config import config def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) bootstrap.init_app(app) db.init_app(app) moment.init_app(app) from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app
Finally to round out the /app
directory, create two empty files: decorators.py
and models.py
, as well as a quick exceptions.py
file with a ValidationError
function:
app/exceptions.py
class ValidationError(ValueError): pass
We will talk more about the models and decorators next week, but these are used in almost every Flask application, so like the packages we installed earlier, I’ve found it’s better to get in the habit of creating them with every new project.
Main Course
Next on our docket is to create /main
directory for actually returning something when a user visits your page. Create an init.py
file in /main
, followed by views.py
. In init.py
, we’ll make our blueprint.
app/main/init.py
from flask import Blueprint main = Blueprint(‘main’, __name__) from . import views
And we will create a basic “hello world” endpoint as a sanity check for when we’re done.
app/main/views.py
from . import main @main.route(‘/’) def index(): return “Hello World!”, 200
Finishing up
In our last few steps, we are going to create an application.py
and config.py
file in our main project directory. This will run the create_app
function that we made in the app/init.py
file, to operate as the entry point for the web app.
application.py
import os from app import create_app, db app = create_app(os.getenv(‘FLASK_CONFIG’) or ‘default’)
The config.py
file will organize all of the different project-wide settings as well as help differentiate between development, testing, and production settings for our database.
config.py
import os basedir = os.path.abspath(os.path.dirname(__file__)) class Config: SECRET_KEY = os.environ.get(‘SECRET_KEY’, ‘secret’) STREAM_API_KEY = ‘’#Insert your Stream API key her STREAM_SECRET = ‘’#Insert your Stream Secret here @staticmethod def init_app(app): pass class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get(‘DEV_DATABASE_URL’) or \ ‘sqlite:///’ + os.path.join(basedir, ‘data-dev.sqlite’) class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get(‘TEST_DATABASE_URL’) or \ ‘sqlite://’ WTF_CSRF_ENABLED = False class ProductionConfig(Config): SQLALCHEMY_DATABASE_URI = os.environ.get(‘DATABASE_URL’) or \ ‘sqlite:///’ + os.path.join(basedir, ‘data/sqlite’) @classmethod def init_app(cls, app): Config.init_app(app) config = { ‘development’: DevelopmentConfig, ‘testing’: TestingConfig, ‘production’: ProductionConfig, ‘default’: DevelopmentConfig }
Final Thoughts
You now should have the basic structure in place to build a Flask Application. To run the sanity check I mentioned earlier to make sure everything is working the way it should, go to the venv
activated command line:
(Windows)
https://gist.github.com/Porter97/5374a9d557df56bee4f48377327e6edb
Now, if you navigate in your web browser to localhost (http://127.0.0.1:5000), you should see Hello World!
See you next week, where we’ll be starting to building out our web app with users and permissions levels, as well as some necessary forms for registration and login/logout.
Happy Coding!
Note: The next post in this series can be found here.