Shopyo is a framework to get started with Flask really quick. It includes several libraries to get started by default. In this tutorial we will build a simple app to get started with. We used it for FlaskCon 2021 [site, codebase]. This tuto's app is available here
First steps
The first step is to install the library.
python3.9 -m venv venv # create virtual env
. venv/bin/activate # activate (linux version)
pip install shopyo==4.4.3
Then we create our folder
mkdir note_app
We enter into the folder
cd note_app
Then we create a new Shopyo project
shopyo new
The output looks like this:
creating project note_app...
#######################
[x] Project note_app created successfully!
A tree lookup gives
├── docs
│ ├── conf.py
│ ├── docs.rst
│ ├── index.rst
│ ├── Makefile
│ └── _static
│ └── custom.css
├── MANIFEST.in
├── note_app
├── pytest.ini
├── README.md
├── requirements.txt
├── setup.py
└── tox.ini
Since we are not interested in packaging our app for now, we can switch to the inner note_app/ folder
cd note_app
The inner note_app folder has this structure
├── note_app
│ ├── app.py
│ ├── app.txt
│ ├── autoapp.py
│ ├── CHANGELOG.md
│ ├── cli.py
│ ├── config_demo.json
│ ├── config.py
│ ├── conftest.py
│ ├── __init__.py
│ ├── init.py
│ ├── manage.py
│ ├── modules
│ ├── shopyo_admin.py
│ ├── static
│ ├── tests
│ │ ├── conftest.py
│ │ └── test_configs.py
│ └── wsgi.py
Creating modules
Lets create the notes app
shopyo startapp notes
A new folder will be created under modules/
. The content of modules/note_app/
looks like this
modules/notes/
├── forms.py
├── global.py
├── info.json
├── models.py
├── static
├── templates
│ └── notes
│ ├── blocks
│ │ └── sidebar.html
│ └── dashboard.html
├── tests
│ ├── test_notes_functional.py
│ └── test_notes_models.py
└── view.py
These are files created by default.
Writing the first view
The info.json
file lists some basics about the module, including it's url namespace (module_name) and url prefix
{
"author": {
"mail": "",
"name": "",
"website": ""
},
"display_string": "Notes",
"fa-icon": "fa fa-store",
"module_name": "notes",
"type": "show",
"url_prefix": "/notes"
}
Let's change url_prefix
to "/"
{
...,
"url_prefix": "/"
}
Our view.py
looks like this, which is generated by default.
from shopyo.api.module import ModuleHelp
mhelp = ModuleHelp(__file__, __name__)
globals()[mhelp.blueprint_str] = mhelp.blueprint
module_blueprint = globals()[mhelp.blueprint_str]
@module_blueprint.route("/")
def index():
return mhelp.info['display_string']
Let's change the return string to String from notes app
@module_blueprint.route("/")
def index():
return "String from notes app"
Running the app
Run shopyo rundebug
to run the app in debug mode.
Going to "http://127.0.0.1:5000/" should return "String from notes app"
You can learn more about the run command here.
Creating models
Our notes will have a title and a content. In modules/notes/models.py
write:
from init import db
from shopyo.api.models import PkModel
class Note(PkModel):
__tablename__ = 'notes'
title = db.Column(db.String(80), nullable=False)
content = db.Text()
The init
import comes from the init.py
file.
The PkModel
is same as db.Model
with by default id
as primary key
Then we initialise the app. It uses Flask-Migrate under the hood. You can view more initialise options here
$ shopyo initialise
initializing...
Cleaning...
#######################
Auto importing models...
#######################
Creating db...
#######################
Migrating db...
#######################
Upgrading db...
#######################
Collecting static...
#######################
Uploading initial data to db...
#######################
All Done!
This worked as Shopyo adds a shopyo.db
as basic sqlalchemy connection string.
Configuring Flask-Admin
Now let's configure flask-admin to have a quick CRUD view. Fortunately, Shopyo already has some basics ongoing.
First, modify shopyo_admin.py
to remove Flask-Login authentications
from flask import redirect
from flask import request
from flask import url_for
from flask_admin import AdminIndexView
from flask_admin import expose
from flask_admin.contrib import sqla as flask_admin_sqla
from flask_login import current_user
class DefaultModelView(flask_admin_sqla.ModelView):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# def is_accessible(self):
# return current_user.is_authenticated and current_user.is_admin
# def inaccessible_callback(self, name, **kwargs):
# # redirect to login page if user doesn't have access
# return redirect(url_for("auth.login", next=request.url))
class MyAdminIndexView(AdminIndexView):
# def is_accessible(self):
# return current_user.is_authenticated and current_user.is_admin
# def inaccessible_callback(self, name, **kwargs):
# # redirect to login page if user doesn't have access
# return redirect(url_for("auth.login", next=request.url))
@expose("/")
def index(self):
# if not current_user.is_authenticated and current_user.is_admin:
# return redirect(url_for("auth.login"))
return super().index()
#
@expose("/dashboard")
def indexs(self):
# if not current_user.is_authenticated and current_user.is_admin:
# return redirect(url_for("auth.login"))
return super().index()
Then in app.py, don't load Flask-Login by commenting it out.
def load_extensions(app):
...
# login_manager.init_app(app)
Then in app.py
import the Note model
from modules.notes.models import Note
And modify the setup_flask_admin
function to look like this:
def setup_flask_admin(app):
admin = Admin(
app,
name="My App",
template_mode="bootstrap4",
index_view=MyAdminIndexView(),
)
admin.add_view(ModelView(Note, db.session))
Now, navigating to /admin
gives
Clicking on note allows you to edit the Note model. Let's add few models!
Displaying templates
What remains is using displaying the note on our main page.
Under modules/notes/templates/notes
create a file called index.html with content
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
{% for note in notes %}
{{note.title}}<br>
{{note.content}}<hr>
{% endfor %}
</body>
</html>
Modify the view.py to
from shopyo.api.module import ModuleHelp
from flask import render_template
from .models import Note
mhelp = ModuleHelp(__file__, __name__)
globals()[mhelp.blueprint_str] = mhelp.blueprint
module_blueprint = globals()[mhelp.blueprint_str]
@module_blueprint.route("/")
def index():
notes = Note.query.all()
return render_template('notes/index.html', notes=notes)
Which results in:
Shopyo also provides some utils like
from shopyo.api.templates import yo_render
...
@module_blueprint.route("/")
def index():
notes = Note.query.all()
context = {
'notes': notes
}
return yo_render('notes/index.html', context)
Trying out a demo app
If you just want to try a demo app, just run (comment back the flask-login modifications)
mkdir project
cd project
shopyo new -m # -m adds default modules
cd project
shopyo initialise
shopyo rundebug
You can then see how an authed Flask-Admin looks like.
Hope you enjoy this post!
This tuto's app is available here
Top comments (0)