Skip to content

Commit

Permalink
new
Browse files Browse the repository at this point in the history
  • Loading branch information
kenqcl committed Jul 31, 2022
0 parents commit 1bb5297
Show file tree
Hide file tree
Showing 29 changed files with 1,012 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**/venv
**/__pycache__
**/.pytest_cache
**/*.sqlite
95 changes: 95 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Flask Project Scaffold

![book](book.jpg)

## [Flask Web Development, 2nd - O'Reilly 2018](https://www.amazon.com/Flask-Web-Development-Developing-Applications/dp/1491991739/)

Chapter 7 Large Application Structure

## Usage

- Clone this git repo
- Copy `proj` dir to your proj dir, and rename properly
- Create `venv` and activate it
- `python -m venv venv --prompt flask`
- `venv\Scripts\activate`
- `python -m pip install pip --upgrade`
- Install packages `pip install -r requirements.txt`
- set env `FLASK_APP="flask_app"`, `FLASK_ENV="development"`
- Run `flask run`

### Project Structure

```text
|-app/
|-templates/
|-static/
|-main/
|-__init__.py
|-errors.py
|-forms.py
|-views.py
|-__init__.py
|-models.py
|-email.py
|-migrations/
|-tests/
|-__init__.py
|-test*.py
|-venv/
|-requirements.txt
|-config.py
|-flask_appy.py
```

`flask_scaffold.py` create this folder structure

### Application Factory

```python
### file: 'app/__init__.py'

from flask import Flask, render_template
from flask_bootstrap import Bootstrap5 as Bootstrap

from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy

from flask_mail import Mail

from config import config

bootstrap = Bootstrap()
moment = Moment()
db = SQLAlchemy()

mail = Mail()

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)
moment.init_app(app)
db.init_app(app)

mail.init_app(app)

# Register 'main' blueprint
from .main import main as main_bp
app.register_blueprint(main_bp)

return app
```

### Blueprint

```python
### file 'app/main/__init__.py'

from flask import Blueprint
main = Blueprint('main', __name__)

from . import views, errors
Binary file added book.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 100 additions & 0 deletions flask_scaffold.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""
Create Flask application directory structure
- Base on "Flask Web Development, 2nd - O'Reilly 2018" "Chapter 7"
- Be aware: the files are dummy file, empty, wihout content
Usage
-----------------
python flask_scaffold.py <proj_home>
Argument
-----------------
sys.argv[1]: String
project home dir
- can be absolute path, i.e: "D:\temp\proj"
- or relative path, "proj", or ".\proj"
Errors
------------------
if 2nd argument(sys.argv[1]) is not set:
exit -1
"""

import os, sys

"""
Directories to create
- ["app", "templates"] means to create "app/templates" dir
"""
DIRS = [
["app", "templates"], # "app/templates" dir
["app", "static"],
["app", "main"],
["migrations"],
["tests"],
["venv"],
]

"""
Files to create
- ["app", "main", "__init__.py"] means to create "app/main/__init__.py" file
"""
FILES = [
["app", "main", "__init__.py"], # "app/main/__init__.py" file
["app", "main", "errors.py"],
["app", "main", "forms.py"],
["app", "main", "views.py"],
["app", "__init__.py"],
["app", "models.py"],
["app", "email.py"],
["tests", "__init__.py"],
["requirements.txt"],
["config.py"],
["flask_app.py"]
]

def get_proj_home(home):
if os.path.isabs(home):
return home
else:
phome = os.path.abspath(os.path.dirname(__file__))
phome = os.path.join(phome, home)
return phome

def create_dirs_files(home):
from pathlib import Path
for fd in DIRS + FILES:
target =os.path.join(home, *fd)
print("Create: " + target)

# Skip if target exists
if os.path.exists(target):
continue

# for DIRS
if fd in DIRS:
os.makedirs(target)

# for FILES
if fd in FILES:
Path(target).touch()

if __name__ == '__main__':

# Check command line argument, 2nd argument is Proj HOME
if len(sys.argv) < 2:
msg = "Error!\n" + \
"Please specify proj home as:\n" + \
f" python {__file__} abc \n"
print(msg)
exit(-1)

# Get project home
home = get_proj_home(sys.argv[1])
print("Project home: " + home)

# create dirs and files
create_dirs_files(home)


4 changes: 4 additions & 0 deletions proj/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**/venv
**/__pycache__
**/.pytest_cache
**/*.sqlite
31 changes: 31 additions & 0 deletions proj/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from flask import Flask, render_template
from flask_bootstrap import Bootstrap5 as Bootstrap

from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy

from flask_mail import Mail

from config import config

bootstrap = Bootstrap()
moment = Moment()
db = SQLAlchemy()

mail = Mail()

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)
moment.init_app(app)
db.init_app(app)

mail.init_app(app)

from .main import main as main_bp
app.register_blueprint(main_bp)

return app
Empty file added proj/app/email.py
Empty file.
6 changes: 6 additions & 0 deletions proj/app/main/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from flask import Blueprint

main = Blueprint('main', __name__)

from . import views, errors

11 changes: 11 additions & 0 deletions proj/app/main/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from flask import render_template
from . import main

@main.app_errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404

@main.app_errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500

7 changes: 7 additions & 0 deletions proj/app/main/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):
name = StringField('Your name:', validators=[DataRequired()])
submit = SubmitField('Submit')
28 changes: 28 additions & 0 deletions proj/app/main/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from datetime import datetime

from flask import render_template, session, redirect, url_for

from . import main
from .forms import NameForm
from .. import db
from ..models import User

@main.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username=form.name.data)
db.session.add(user)
db.session.commit()
session['known'] = False
else:
session['known'] = True
return redirect(url_for('.index'))

return render_template('index.html',
title="Home",
form=form,
name=session.get('name'),
known=session.get('known', False)) #
21 changes: 21 additions & 0 deletions proj/app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from . import db


class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role', lazy='dynamic')

def __repr__(self):
return '<Role %r>' % self.name


class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

def __repr__(self):
return '<User %r>' % self.username
11 changes: 11 additions & 0 deletions proj/app/templates/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends "base.html" %}

{% block title %}
Page not found (404)
{% endblock %}

{% block page_content %}
<div class="page-header">
<h1>Sorry, Page not found (404)</h1>
</div>
{% endblock %}
12 changes: 12 additions & 0 deletions proj/app/templates/500.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "base.html" %}

{% block title %}
Page not found (404)
{% endblock %}

{% block page_content %}
<div class="page-header">
<h1>Sorry, Internal Error (500)</h1>
</div>
{% endblock %}

Loading

0 comments on commit 1bb5297

Please sign in to comment.