Code Journal R2D5 100 Days of Code 2019-08-30
Posted on Fri 30 August 2019 in Python • 3 min read
The first couple of days of this second round of #100DaysOfCode I went through almost all the Flask tutorials in #100DaysOfWeb in Python) . They are:
- Flask Intro
- Calling APIs in Flask
- Flask Login
As an extension to that I wanted to build my own app from scratch, in a way to state the knowledge I gained in these tutorials. I decided to build a Flask app where a user can sign up, login, change their profile, and write a code diary. In the end I will also publish it to Heroku, PythonAnywhere or something similar. Just to get the whole thing from building to publishing.
The code diary will contain the fields:
- Title
- Description
- Link (optional link to e.g. a repo or commit)
So, today I set up the basic structure of the app. Used a somewhat different structure than from the tutorials. And also I use Flask Blueprints.
Project Structure
The project structure I’ve done today, looks like this:
Models
This is how I made the models.
User model:
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from app import db
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), unique=False, nullable=False)
firstname = db.Column(db.String(100), unique=False)
lastname = db.Column(db.String(100), unique=False)
email = db.Column(db.String(100))
diaries = db.relationship('Diary', backref='user', lazy=True)
def __repr__(self):
return f'User {self.username}'
Diary model:
from app import db
class Diary(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
description = db.Column(db.String(500))
link = db.Column(db.String(256))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f'Diary {self.title}'
I’ve implemented almost the same login model as in the Flask Login tutorial mentioned above, but implemented it as a Flask Blueprint which I registered in the global routes.py
.
from app import app
from app.views.users import user_blueprint
from flask import render_template
app.register_blueprint(user_blueprint, url_prefix='/users')
@app.route('/')
def index():
return render_template('index.html')
Migrations
I am also using Flask-Migrate in the project to be able to easily handle any changes in the models. For that I’ve made an manage.py
in the root of the project that I can call for different operations, for example:
- Python manage.py db init
- Python manage.py db migrate
- Python manage.py upgrade
- Python manage.py downgrade
Manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app/site_user.db'
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
To run the Flask App i run run.py
which only contains this:
from app import app
app.run(debug=True)
Gotcha’s
I managed to put the logout_user
function from Flask-Login into my own function that I happened to call logout_user
and got a nasty recursion error. Changed the name of my function to get it to work.
@user_blueprint.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
Next step
Tomorrow I will start to implement the views and functionality for the Diary model.
Conclusion
A simple Flask App can be as simple as a few files. But when starting to split the parts in a structure with folders for models, views and adding Flask extensions etc, there’s a lot of connections between the parts to get your head around in my opinion. But when the structure is in place it is probably easier to manage when the project grows.