dodal vsebino po flask tutorialu...
parent
955e05460e
commit
ba22b3a03d
|
@ -9,7 +9,7 @@ def create_app(test_config=None):
|
||||||
app.config.from_mapping(
|
app.config.from_mapping(
|
||||||
SECRET_KEY='dev',
|
SECRET_KEY='dev',
|
||||||
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
|
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
|
||||||
)
|
) # = kaj naj tu piše?
|
||||||
|
|
||||||
if test_config is None:
|
if test_config is None:
|
||||||
# load the instance config, if it exists, when not testing
|
# load the instance config, if it exists, when not testing
|
||||||
|
@ -29,4 +29,13 @@ def create_app(test_config=None):
|
||||||
def hello():
|
def hello():
|
||||||
return 'Hello, Woooorld!'
|
return 'Hello, Woooorld!'
|
||||||
|
|
||||||
return app
|
from . import db
|
||||||
|
db.init_app(app)
|
||||||
|
|
||||||
|
from . import auth
|
||||||
|
app.register_blueprint(auth.bp)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
app = create_app()
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
""""
|
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
|
||||||
|
@ -8,7 +7,6 @@ app = Flask(__name__)
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def hello_world():
|
def hello_world():
|
||||||
return "<p>Hello, World!</p>"
|
return "<p>Hello, World!</p>"
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
95
app/auth.py
95
app/auth.py
|
@ -0,0 +1,95 @@
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from flask import (
|
||||||
|
Blueprint, flash, g, redirect, render_template, request, session, url_for
|
||||||
|
)
|
||||||
|
from werkzeug.security import check_password_hash, generate_password_hash
|
||||||
|
|
||||||
|
# from db import get_db error
|
||||||
|
|
||||||
|
bp = Blueprint('auth', __name__, url_prefix='/auth')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/register', methods=('GET', 'POST'))
|
||||||
|
def register():
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form['username']
|
||||||
|
password = request.form['password']
|
||||||
|
db = get_db()
|
||||||
|
error = None
|
||||||
|
|
||||||
|
if not username:
|
||||||
|
error = 'Username is required.'
|
||||||
|
elif not password:
|
||||||
|
error = 'Password is required.'
|
||||||
|
|
||||||
|
if error is None:
|
||||||
|
try:
|
||||||
|
db.execute(
|
||||||
|
"INSERT INTO user (username, password) VALUES (?, ?)",
|
||||||
|
(username, generate_password_hash(password)),
|
||||||
|
)
|
||||||
|
db.commit()
|
||||||
|
except db.IntegrityError:
|
||||||
|
error = f"User {username} is already registered."
|
||||||
|
else:
|
||||||
|
return redirect(url_for("auth.login"))
|
||||||
|
|
||||||
|
flash(error)
|
||||||
|
|
||||||
|
return render_template('auth/register.html')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/login', methods=('GET', 'POST'))
|
||||||
|
def login():
|
||||||
|
if request.method == 'POST':
|
||||||
|
username = request.form['username']
|
||||||
|
password = request.form['password']
|
||||||
|
db = get_db()
|
||||||
|
error = None
|
||||||
|
user = db.execute(
|
||||||
|
'SELECT * FROM user WHERE username = ?', (username,)
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
error = 'Incorrect username.'
|
||||||
|
elif not check_password_hash(user['password'], password):
|
||||||
|
error = 'Incorrect password.'
|
||||||
|
|
||||||
|
if error is None:
|
||||||
|
session.clear()
|
||||||
|
session['user_id'] = user['id']
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
flash(error)
|
||||||
|
|
||||||
|
return render_template('auth/login.html')
|
||||||
|
|
||||||
|
|
||||||
|
@bp.before_app_request
|
||||||
|
def load_logged_in_user():
|
||||||
|
user_id = session.get('user_id')
|
||||||
|
|
||||||
|
if user_id is None:
|
||||||
|
g.user = None
|
||||||
|
else:
|
||||||
|
g.user = get_db().execute(
|
||||||
|
'SELECT * FROM user WHERE id = ?', (user_id,)
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/logout')
|
||||||
|
def logout():
|
||||||
|
session.clear()
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
|
|
||||||
|
def login_required(view):
|
||||||
|
@functools.wraps(view)
|
||||||
|
def wrapped_view(**kwargs):
|
||||||
|
if g.user is None:
|
||||||
|
return redirect(url_for('auth.login'))
|
||||||
|
|
||||||
|
return view(**kwargs)
|
||||||
|
|
||||||
|
return wrapped_view
|
|
@ -0,0 +1,57 @@
|
||||||
|
import sqlite3 ## tu rabim nekaj drugega
|
||||||
|
|
||||||
|
import click
|
||||||
|
from flask import current_app, g
|
||||||
|
from flask.cli import with_appcontext
|
||||||
|
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
if 'db' not in g:
|
||||||
|
g.db = sqlite3.connect(
|
||||||
|
current_app.config['DATABASE'],
|
||||||
|
detect_types=sqlite3.PARSE_DECLTYPES
|
||||||
|
)
|
||||||
|
g.db.row_factory = sqlite3.Row
|
||||||
|
|
||||||
|
return g.db
|
||||||
|
|
||||||
|
|
||||||
|
def close_db(e=None):
|
||||||
|
db = g.pop('db', None)
|
||||||
|
|
||||||
|
if db is not None:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
open_resource() opens a file relative to the flaskr package, which is useful since you won’t necessarily know where that location is when deploying the application later. get_db returns a database connection, which is used to execute the commands read from the file.
|
||||||
|
|
||||||
|
click.command() defines a command line command called init-db that calls the init_db function and shows a success message to the user. You can read Command Line Interface to learn more about writing commands.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def init_db():
|
||||||
|
db = get_db()
|
||||||
|
|
||||||
|
with current_app.open_resource('schema.sql') as f:
|
||||||
|
db.executescript(f.read().decode('utf8'))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('init-db')
|
||||||
|
@with_appcontext
|
||||||
|
def init_db_command():
|
||||||
|
"""Clear the existing data and create new tables."""
|
||||||
|
init_db()
|
||||||
|
click.echo('Initialized the database.')
|
||||||
|
|
||||||
|
def init_app(app):
|
||||||
|
app.teardown_appcontext(close_db)
|
||||||
|
app.cli.add_command(init_db_command)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
app.teardown_appcontext() tells Flask to call that function when cleaning up after returning the response.
|
||||||
|
|
||||||
|
app.cli.add_command() adds a new command that can be called with the flask command.
|
||||||
|
"""
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
background: #eee;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: serif;
|
||||||
|
color: #377ba8;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #377ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
background: lightgray;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav h1 {
|
||||||
|
flex: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav h1 a {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul li a, nav ul li span, header .action {
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 1rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > header {
|
||||||
|
border-bottom: 1px solid lightgray;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > header h1 {
|
||||||
|
flex: auto;
|
||||||
|
margin: 1rem 0 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flash {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 1em;
|
||||||
|
background: #cae6f6;
|
||||||
|
border: 1px solid #377ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post > header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post > header > div:first-of-type {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post > header h1 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post .about {
|
||||||
|
color: slategray;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post .body {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content form {
|
||||||
|
margin: 1em 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content label {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content input, .content textarea {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content textarea {
|
||||||
|
min-height: 12em;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.danger {
|
||||||
|
color: #cc2f2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit] {
|
||||||
|
align-self: start;
|
||||||
|
min-width: 10em;
|
||||||
|
}
|
Loading…
Reference in New Issue