Working Example
This commit is contained in:
2
Pipfile
2
Pipfile
@@ -7,6 +7,8 @@ name = "pypi"
|
||||
flask = "*"
|
||||
flask_wtf = "*"
|
||||
flask-login = "*"
|
||||
flask-sqlalchemy = "*"
|
||||
flask-migrate = "*"
|
||||
|
||||
[dev-packages]
|
||||
pylint = "*"
|
||||
|
||||
146
Pipfile.lock
generated
146
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "6f468a10e748aa502127b19811e3cb91bc60a239cbe1c6fa7cc3d0a90dc9ab30"
|
||||
"sha256": "6d1e954a069f0d93d3fff2ba6d3bd3a08da50fa809099a6b572b3a9d97905749"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -16,6 +16,13 @@
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"alembic": {
|
||||
"hashes": [
|
||||
"sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51",
|
||||
"sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c"
|
||||
],
|
||||
"version": "==1.6.5"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a",
|
||||
@@ -39,6 +46,22 @@
|
||||
"index": "pypi",
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"flask-migrate": {
|
||||
"hashes": [
|
||||
"sha256:4d42e8f861d78cb6e9319afcba5bf76062e5efd7784184dd2a1cccd9de34a702",
|
||||
"sha256:df9043d2050df3c0e0f6313f6b529b62c837b6033c20335e9d0b4acdf2c40e23"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"flask-sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912",
|
||||
"sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.5.1"
|
||||
},
|
||||
"flask-wtf": {
|
||||
"hashes": [
|
||||
"sha256:6ff7af73458f182180906a37a783e290bdc8a3817fe4ad17227563137ca285bf",
|
||||
@@ -47,6 +70,61 @@
|
||||
"index": "pypi",
|
||||
"version": "==0.15.1"
|
||||
},
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
"sha256:03f28a5ea20201e70ab70518d151116ce939b412961c33827519ce620957d44c",
|
||||
"sha256:06d7ac89e6094a0a8f8dc46aa61898e9e1aec79b0f8b47b2400dd51a44dbc832",
|
||||
"sha256:06ecb43b04480e6bafc45cb1b4b67c785e183ce12c079473359e04a709333b08",
|
||||
"sha256:096cb0217d1505826ba3d723e8981096f2622cde1eb91af9ed89a17c10aa1f3e",
|
||||
"sha256:0c557c809eeee215b87e8a7cbfb2d783fb5598a78342c29ade561440abae7d22",
|
||||
"sha256:0de64d419b1cb1bfd4ea544bedea4b535ef3ae1e150b0f2609da14bbf48a4a5f",
|
||||
"sha256:14927b15c953f8f2d2a8dffa224aa78d7759ef95284d4c39e1745cf36e8cdd2c",
|
||||
"sha256:16183fa53bc1a037c38d75fdc59d6208181fa28024a12a7f64bb0884434c91ea",
|
||||
"sha256:206295d270f702bc27dbdbd7651e8ebe42d319139e0d90217b2074309a200da8",
|
||||
"sha256:22002259e5b7828b05600a762579fa2f8b33373ad95a0ee57b4d6109d0e589ad",
|
||||
"sha256:2325123ff3a8ecc10ca76f062445efef13b6cf5a23389e2df3c02a4a527b89bc",
|
||||
"sha256:258f9612aba0d06785143ee1cbf2d7361801c95489c0bd10c69d163ec5254a16",
|
||||
"sha256:3096286a6072553b5dbd5efbefc22297e9d06a05ac14ba017233fedaed7584a8",
|
||||
"sha256:3d13da093d44dee7535b91049e44dd2b5540c2a0e15df168404d3dd2626e0ec5",
|
||||
"sha256:408071b64e52192869129a205e5b463abda36eff0cebb19d6e63369440e4dc99",
|
||||
"sha256:598bcfd841e0b1d88e32e6a5ea48348a2c726461b05ff057c1b8692be9443c6e",
|
||||
"sha256:5d928e2e3c3906e0a29b43dc26d9b3d6e36921eee276786c4e7ad9ff5665c78a",
|
||||
"sha256:5f75e7f237428755d00e7460239a2482fa7e3970db56c8935bd60da3f0733e56",
|
||||
"sha256:60848099b76467ef09b62b0f4512e7e6f0a2c977357a036de602b653667f5f4c",
|
||||
"sha256:6b1d08f2e7f2048d77343279c4d4faa7aef168b3e36039cba1917fffb781a8ed",
|
||||
"sha256:70bd1bb271e9429e2793902dfd194b653221904a07cbf207c3139e2672d17959",
|
||||
"sha256:76ed710b4e953fc31c663b079d317c18f40235ba2e3d55f70ff80794f7b57922",
|
||||
"sha256:7920e3eccd26b7f4c661b746002f5ec5f0928076bd738d38d894bb359ce51927",
|
||||
"sha256:7db68f15486d412b8e2cfcd584bf3b3a000911d25779d081cbbae76d71bd1a7e",
|
||||
"sha256:8833e27949ea32d27f7e96930fa29404dd4f2feb13cce483daf52e8842ec246a",
|
||||
"sha256:944fbdd540712d5377a8795c840a97ff71e7f3221d3fddc98769a15a87b36131",
|
||||
"sha256:9a6b035aa2c5fcf3dbbf0e3a8a5bc75286fc2d4e6f9cfa738788b433ec894919",
|
||||
"sha256:9bdcff4b9051fb1aa4bba4fceff6a5f770c6be436408efd99b76fc827f2a9319",
|
||||
"sha256:a9017ff5fc2522e45562882ff481128631bf35da444775bc2776ac5c61d8bcae",
|
||||
"sha256:aa4230234d02e6f32f189fd40b59d5a968fe77e80f59c9c933384fe8ba535535",
|
||||
"sha256:ad80bb338cf9f8129c049837a42a43451fc7c8b57ad56f8e6d32e7697b115505",
|
||||
"sha256:adb94a28225005890d4cf73648b5131e885c7b4b17bc762779f061844aabcc11",
|
||||
"sha256:b3090631fecdf7e983d183d0fad7ea72cfb12fa9212461a9b708ff7907ffff47",
|
||||
"sha256:b33b51ab057f8a20b497ffafdb1e79256db0c03ef4f5e3d52e7497200e11f821",
|
||||
"sha256:b97c9a144bbeec7039cca44df117efcbeed7209543f5695201cacf05ba3b5857",
|
||||
"sha256:be13a18cec649ebaab835dff269e914679ef329204704869f2f167b2c163a9da",
|
||||
"sha256:be9768e56f92d1d7cd94185bab5856f3c5589a50d221c166cc2ad5eb134bd1dc",
|
||||
"sha256:c1580087ab493c6b43e66f2bdd165d9e3c1e86ef83f6c2c44a29f2869d2c5bd5",
|
||||
"sha256:c35872b2916ab5a240d52a94314c963476c989814ba9b519bc842e5b61b464bb",
|
||||
"sha256:c70c7dd733a4c56838d1f1781e769081a25fade879510c5b5f0df76956abfa05",
|
||||
"sha256:c767458511a59f6f597bfb0032a1c82a52c29ae228c2c0a6865cfeaeaac4c5f5",
|
||||
"sha256:c87df8ae3f01ffb4483c796fe1b15232ce2b219f0b18126948616224d3f658ee",
|
||||
"sha256:ca1c4a569232c063615f9e70ff9a1e2fee8c66a6fb5caf0f5e8b21a396deec3e",
|
||||
"sha256:cc407b68e0a874e7ece60f6639df46309376882152345508be94da608cc0b831",
|
||||
"sha256:da862b8f7de577bc421323714f63276acb2f759ab8c5e33335509f0b89e06b8f",
|
||||
"sha256:dfe7eac0d253915116ed0cd160a15a88981a1d194c1ef151e862a5c7d2f853d3",
|
||||
"sha256:ed1377feed808c9c1139bdb6a61bcbf030c236dd288d6fca71ac26906ab03ba6",
|
||||
"sha256:f42ad188466d946f1b3afc0a9e1a266ac8926461ee0786c06baac6bd71f8a6f3",
|
||||
"sha256:f92731609d6625e1cc26ff5757db4d32b6b810d2a3363b0ff94ff573e5901f6f"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c",
|
||||
@@ -61,6 +139,13 @@
|
||||
],
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"mako": {
|
||||
"hashes": [
|
||||
"sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab",
|
||||
"sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e"
|
||||
],
|
||||
"version": "==1.1.4"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
|
||||
@@ -100,6 +185,65 @@
|
||||
],
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||
],
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"python-editor": {
|
||||
"hashes": [
|
||||
"sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d",
|
||||
"sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b",
|
||||
"sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8",
|
||||
"sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77",
|
||||
"sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"
|
||||
],
|
||||
"version": "==1.0.4"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sqlalchemy": {
|
||||
"hashes": [
|
||||
"sha256:0f6d467b67a7e5048f1408e8ea60d6caa70be5b386d0eebbf1185ab49cb8c7e4",
|
||||
"sha256:238d78b3110b7f7cffdb70bf9cda686e0d876a849bc78ba4d471aa7b1461f306",
|
||||
"sha256:25c0e0f3a7e8c19350086b3c0fe93c4def045cec053d749ef15da710c4d54c81",
|
||||
"sha256:2f60a2e599cf5cf5e5327ce60f2918b897e42ad9f405d10dd01e37869c0ce6fc",
|
||||
"sha256:38ee3a266afef2978e82824650457f70c5d74ec0cadec1b10fe5ed6f038eb5d0",
|
||||
"sha256:46361690f1e1c5385994a4caeb6e8126063ff593a5c635700bbc1245de793c1e",
|
||||
"sha256:46b99eab618cdc1c871ea707b7c52edc23cfea6c750740cd242ba62b5c84de7f",
|
||||
"sha256:4a67371752fd86d1d03a3b82d4e75404608f6f4d579b9676124079a22a40c79f",
|
||||
"sha256:525dd3c2205b11a2bc6d770bf1ec63bde0253fd754b4c19c399d27ddc9dad0d3",
|
||||
"sha256:6c8406c3d8c1c7d15da454de15d77f7bb48d14ede5db994f74226c348cf1050e",
|
||||
"sha256:6da83225a23eaf7b3f48f3d5f53c91b2cf00fbfa48b24a7a758160112dd3e123",
|
||||
"sha256:7150e5b543b466f45f668b352f7abda27998cc8035f051d1b7e9524ca9eb2f5f",
|
||||
"sha256:76fbc24311a3d039d6cd147d396719f606d96d1413f3816c028a48e29367f646",
|
||||
"sha256:854a7b15750e617e16f8d65dbc004f065a7963544b253b923f16109557648777",
|
||||
"sha256:86c079732328f1add097b0b8079cd532b5d28e207fac93e9d6ea5f487506deef",
|
||||
"sha256:8d860c62e3f51623ccd528d8fac44580501df557d4b467cc5581587fcf057719",
|
||||
"sha256:9675d5bc7e4f96a7bb2b54d14e9b269a5fb6e5d36ecc7d01f0f65bb9af3185f9",
|
||||
"sha256:9841762d114018c49483c089fa2d47f7e612e57666323f615913d7d7f46e9606",
|
||||
"sha256:9eb25bcf9161e2fcbe9eebe8e829719b2334e849183f0e496bf4b83722bcccfa",
|
||||
"sha256:aad3234a41340e9cf6184e621694e2a7233ba3f8aef9b1e6de8cba431b45ebd2",
|
||||
"sha256:b502b5e2f08500cc4b8d29bfc4f51d805adcbc00f8d149e98fda8aae85ddb644",
|
||||
"sha256:b86d83fefc8a8c394f3490c37e1953bc16c311a3d1d1cf91518793bfb9847fb4",
|
||||
"sha256:c0eb2cd3ad4967fcbdd9e066e8cd91fe2c23c671dbae9952f0b4d3d42832cc5f",
|
||||
"sha256:e0d48456e1aa4f0537f9c9af7be71e1f0659ff68bc1cd538ebc785f6b007bd0d",
|
||||
"sha256:eaee5dd378f6f0d7c3ec49aeeb26564d55ac0ad73b9b4688bf29e66deabddf73",
|
||||
"sha256:f14acb0fd16d404fda9370f93aace682f284340c89c3442ac747c5466ac7e2b5",
|
||||
"sha256:f6fc526bd70898489d02bf52c8f0632ab377592ae954d0c0a5bb38d618dddaa9",
|
||||
"sha256:fcd84e4d46a86291495d131a7824ba38d2e8278bda9425c50661a04633174319",
|
||||
"sha256:ff38ecf89c69a531a7326c2dae71982edfe2f805f3c016cdc5bfd1a04ebf80cb",
|
||||
"sha256:ff8bebc7a9d297dff2003460e01db2c20c63818b45fb19170f388b1a72fe5a14"
|
||||
],
|
||||
"version": "==1.4.20"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42",
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from flask import Flask
|
||||
from config import Config
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_login import LoginManager
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = "fdsaGHJ768fdsGHKJHG656&*(&%&*(fsd"
|
||||
app.config.from_object(Config)
|
||||
db = SQLAlchemy(app)
|
||||
migrate = Migrate(app, db)
|
||||
login = LoginManager(app)
|
||||
login.login_view = "login"
|
||||
|
||||
from app import routes
|
||||
from app import routes, models
|
||||
|
||||
@@ -6,5 +6,4 @@ from wtforms.validators import DataRequired
|
||||
class LoginForm(FlaskForm):
|
||||
username = StringField("Username", validators=[DataRequired()])
|
||||
password = PasswordField("Password", validators=[DataRequired()])
|
||||
remember_me = BooleanField("Remember Me")
|
||||
submit = SubmitField("Sign In")
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from flask_login import UserMixin
|
||||
from app import login
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
from app import db, login
|
||||
|
||||
|
||||
class User(UserMixin):
|
||||
class User(UserMixin, db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(64), index=True, unique=True)
|
||||
email = db.Column(db.String(120), index=True, unique=True)
|
||||
password_hash = db.Column(db.String(128))
|
||||
|
||||
def __repr__(self):
|
||||
return "<User {}>".format(self.username)
|
||||
|
||||
def set_password(self, password):
|
||||
self.password_hash = generate_password_hash(password)
|
||||
|
||||
@@ -13,4 +22,4 @@ class User(UserMixin):
|
||||
|
||||
@login.user_loader
|
||||
def load_user(id):
|
||||
return 0
|
||||
return User.query.get(int(id))
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
from flask import render_template, flash, redirect, url_for
|
||||
from flask import flash, redirect, render_template, url_for
|
||||
from flask_login import current_user, login_required, login_user, logout_user
|
||||
|
||||
from app import app
|
||||
from app.forms import LoginForm
|
||||
from flask_login import current_user, login_user, login_required
|
||||
from app.models import User
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@app.route("/index")
|
||||
@login_required
|
||||
def index():
|
||||
user = {"username": "Miguel"}
|
||||
return render_template("index.html", title="Home", user=user)
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
@@ -20,13 +29,7 @@ def login():
|
||||
return render_template("login.html", title="Sign In", form=form)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@app.route("/index")
|
||||
@login_required
|
||||
def index():
|
||||
user = {"username": "Miguel"}
|
||||
posts = [
|
||||
{"author": {"username": "John"}, "body": "Beautiful day in Portland!"},
|
||||
{"author": {"username": "Susan"}, "body": "The Avengers movie was so cool!"},
|
||||
]
|
||||
return render_template("index.html", title="Home", user=user, posts=posts)
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@@ -4,11 +4,17 @@
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
{{ form.username.label }}<br>
|
||||
{{ form.username(size=32) }}
|
||||
{{ form.username(size=32) }}<br>
|
||||
{% for error in form.username.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>
|
||||
{{ form.password.label }}<br>
|
||||
{{ form.password(size=32) }}
|
||||
{{ form.password(size=32) }}<br>
|
||||
{% for error in form.password.errors %}
|
||||
<span style="color: red;">[{{ error }}]</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form>
|
||||
|
||||
9
config.py
Normal file
9
config.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import os
|
||||
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
class Config(object):
|
||||
SECRET_KEY = os.environ.get("SECRET_KEY") or "dfsads1!FASASF231(*&FADSs"
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") or "sqlite:///" + os.path.join(basedir, "app.db")
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
1
migrations/README
Normal file
1
migrations/README
Normal file
@@ -0,0 +1 @@
|
||||
Generic single-database configuration.
|
||||
50
migrations/alembic.ini
Normal file
50
migrations/alembic.ini
Normal file
@@ -0,0 +1,50 @@
|
||||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# template used to generate migration files
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic,flask_migrate
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[logger_flask_migrate]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = flask_migrate
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
||||
91
migrations/env.py
Normal file
91
migrations/env.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from __future__ import with_statement
|
||||
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
config = context.config
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
logger = logging.getLogger('alembic.env')
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
# from myapp import mymodel
|
||||
# target_metadata = mymodel.Base.metadata
|
||||
config.set_main_option(
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
||||
'%', '%%'))
|
||||
target_metadata = current_app.extensions['migrate'].db.metadata
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url, target_metadata=target_metadata, literal_binds=True
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
|
||||
# this callback is used to prevent an auto-migration from being generated
|
||||
# when there are no changes to the schema
|
||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||
def process_revision_directives(context, revision, directives):
|
||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||
script = directives[0]
|
||||
if script.upgrade_ops.is_empty():
|
||||
directives[:] = []
|
||||
logger.info('No changes in schema detected.')
|
||||
|
||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata,
|
||||
process_revision_directives=process_revision_directives,
|
||||
**current_app.extensions['migrate'].configure_args
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
24
migrations/script.py.mako
Normal file
24
migrations/script.py.mako
Normal file
@@ -0,0 +1,24 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
38
migrations/versions/ca4165261e83_users_table.py
Normal file
38
migrations/versions/ca4165261e83_users_table.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""users table
|
||||
|
||||
Revision ID: ca4165261e83
|
||||
Revises:
|
||||
Create Date: 2021-07-03 19:24:44.648471
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ca4165261e83'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('username', sa.String(length=64), nullable=True),
|
||||
sa.Column('email', sa.String(length=120), nullable=True),
|
||||
sa.Column('password_hash', sa.String(length=128), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True)
|
||||
op.create_index(op.f('ix_user_username'), 'user', ['username'], unique=True)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_index(op.f('ix_user_username'), table_name='user')
|
||||
op.drop_index(op.f('ix_user_email'), table_name='user')
|
||||
op.drop_table('user')
|
||||
# ### end Alembic commands ###
|
||||
7
tr.py
7
tr.py
@@ -1 +1,6 @@
|
||||
from app import app
|
||||
from app import app, db
|
||||
from app.models import User
|
||||
|
||||
@app.shell_context_processor
|
||||
def make_shell_context():
|
||||
return {'db': db, 'User': User}
|
||||
|
||||
7
users.json
Normal file
7
users.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"1": {
|
||||
"username": "root",
|
||||
"email": "root@example.com",
|
||||
"password": "123"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user