Je crée une application Web avec Flask et j'ai du code qui pourrait être réutilisé, alors je vais le partager. Nous n'avons pas mentionné quel code fournit quelle fonctionnalité, alors faites vos propres recherches.
Installez à l'avance l'extension à utiliser cette fois. Vous n'avez pas besoin de spécifier la version car toutes les dernières seront préparées.
requirements.txt
Flask
Flask-Login
Flask-Migrate
Flask-SQLAlchemy
Flask-WTF
SQLAlchemy
Werkzeug
WTForms
Jinja2
email-validator
pip install -r requirements.txt
Flask utilise quelque chose appelé «Blueprint» pour diviser la fonctionnalité.
├───main.py # main app.py file to be called to start server for web app
├───requirements.txt # File of pip install statements for your app
├───migrations # folder created for migrations by calling
├───myproject # main project folder, sub-components will be in separate folders
│ │ data.sqlite
│ │ models.py
│ │ __init__.py
│ │
│ │───auth
│ │ │ forms.py
│ │ │ views.py
│ │ │
│ │ │───templates
│ │ │ └───auth
│ │ │ login.html
│ │ │ signup.html
│ │
│ ├───static # Where you store your CSS, JS, Images, Fonts, etc...
│ ├───templates
│ base.html
│ home.html
Dans cette configuration, __init __. Py
contient config
, mais vous pouvez le séparer en config.py
.
Nous avons préparé une mise en page commune pour base.html
et l'avons réutilisée comme {{% extend" base.html "%}} ʻen utilisant un moteur de modèle appelé
jinja2 (
layout. Le nom hmtl` est également souvent utilisé).
J'utilise SQLite
pour SQL, mais je ne peux pas déployer sur Heroku
et ce n'est pas adapté à la mise à l'échelle, donc lorsque vous utilisez SQL, il est préférable d'utiliser réellement MySQL
ou PostgreSQL
. Je pense. Puisque nous utilisons ʻORM appelé
SQLAlchemypour gérer la base de données, le même code peut être utilisé même si le SQL est différent (la configuration est différente).
data.sqlite`` migrations` est un fichier / dossier créé par vous-même.
C'est une demande de Blueprint
d'avoir une structure redondante comme myproject \ auth \ templates \ auth
.
ʻAuth \ forms.py reçoit les formulaires d'inscription et de connexion, et ʻauth \ views.py
reçoit les données saisies à partir des formulaires, les traite et les rend.
main.py
et __ init __. py
Puisque main.py ne fait que des appels, cela ressemble à ceci:
main.py
from flask import render_template
from myproject import app
@app.route('/')
def index():
return render_template('home.html')
if __name__ == '__main__':
app.run(debug=True)
Ce fichier s'enregistre avec la configuration et le plan, et effectue toute l'initialisation.
__init__.py
import os
from flask import Flask, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
login_manager = LoginManager()
app = Flask(__name__, static_folder='static', template_folder='templates')
basedir = os.path.abspath(os.path.dirname(__file__))
#Si vous ajoutez le module complémentaire Heroku Postgres, la variable d'environnement DATABASE_Vers l'URL
#Cette valeur est définie car l'URL de destination de connexion de la base de données PostgreSQL est définie.
#Une fois réglé(Lors de l'exécution sur Heroku)Utilise le,
#Lorsqu'il n'est pas défini(Débogage local, etc.)Le fait utiliser la base de données SQLite locale.
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SECRET_KEY'] = 'mysecretkey'
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Migrate(app, db)
#Assurez-vous d'importer ici après avoir terminé la définition de db
from myproject.auth.views import auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/authenticate')
login_manager.init_app(app)
login_manager.login_view = "auth.login"
La dernière ligne, login_manager.login_view =" auth.login "
, fait référence à l'écran de connexion qui est redirigé lorsque vous essayez d'y accéder, même s'il a @ login_required
.
Par exemple, si vous essayez d'aller dans \ logout
alors que vous n'êtes pas connecté, la fonction de connexion définie dans views.py
sera appelée (puisque l'écran de connexion est rendu par le retour de la fonction, allez à cet écran. Masu).
La table est définie dans models.py
. Je garde mon nom d'utilisateur, mon adresse e-mail et mon mot de passe haché.
En passant, la raison pour laquelle le bouton "Mot de passe oublié?" Ne vous indique pas le mot de passe est qu'il ne reste pas dans la base de données en premier lieu, vous ne pouvez donc pas le dire.
models.py
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from myproject import db, login_manager
@login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
def __init__(self, email, username, password):
self.email = email
self.username = username
self.password_hash = generate_password_hash(password)
def check_password(self,password):
return check_password_hash(self.password_hash, password)
Il est destiné à l'inscription des utilisateurs généraux. L'utilisateur
Entrer le.
Le premier est le formulaire d'inscription.
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired,Email,EqualTo
class SignupForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(),Email()])
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired(), EqualTo('pass_confirm', message='Passwords Must Match!')])
pass_confirm = PasswordField('Confirm password', validators=[DataRequired()])
submit = SubmitField('Sign Up')
Vient ensuite le traitement interne. Le nom d'utilisateur et l'adresse e-mail ne doivent pas se chevaucher dans la base de données, donc s'ils correspondent dans la base de données, une erreur sera émise et vous serez invité à les saisir à nouveau.
Si vous vous inscrivez avec succès, vous serez redirigé vers le formulaire de connexion.
views.py
from flask import (Blueprint, render_template,
redirect, url_for, request,
flash, abort)
from flask_login import login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from myproject import db, app
from myproject.models import User
from myproject.auth.forms import LoginForm, SignupForm
auth_blueprint = Blueprint('auth',
__name__,
template_folder='templates/auth')
@auth_blueprint.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignupForm()
if form.validate_on_submit():
if User.query.filter_by(email=form.email.data).first():
flash('Email has been registered already!')
redirect(url_for('auth.signup'))
elif User.query.filter_by(username=form.username.data).first():
flash('Username has been registered already!')
redirect(url_for('auth.signup'))
else:
user = User(email=form.email.data,
username=form.username.data,
password=form.password.data)
db.session.add(user)
db.session.commit()
flash('Now You can login!')
return redirect(url_for('auth.login'))
return render_template('signup.html', form=form)
On suppose qu'un utilisateur général se connectera.
L'utilisateur entre une adresse e-mail et un mot de passe. Il est décrit dans le même fichier que le formulaire d'inscription.
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired,Email,EqualTo
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Log In')
class SignupForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(),Email()])
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired(), EqualTo('pass_confirm', message='Passwords Must Match!')])
pass_confirm = PasswordField('Confirm password', validators=[DataRequired()])
submit = SubmitField('Sign Up')
Vient ensuite le traitement interne. Identifiez l'utilisateur par adresse e-mail. Le mot de passe est comparé à la valeur de hachage du mot de passe de l'utilisateur à l'aide de la fonction check_password
jouée dans models.py
.
Si vous vous connectez avec succès, vous pouvez accéder à n'importe quel emplacement.
En passant, je quitterai également le processus de déconnexion.
views.py
from flask import (Blueprint, render_template,
redirect, url_for, request,
flash, abort)
from flask_login import login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from myproject import db, app
from myproject.models import User
from myproject.auth.forms import LoginForm, SignupForm
auth_blueprint = Blueprint('auth',
__name__,
template_folder='templates/auth')
@auth_blueprint.route('/logout')
@login_required
def logout():
logout_user()
flash('You logged out!')
return redirect(url_for('index'))
@auth_blueprint.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is None:
flash('something wrong!')
redirect(url_for('auth.login'))
elif user.check_password(form.password.data):
login_user(user)
flash('Logged in successfully.')
# login => somewhere
return redirect(url_for('somewhere'))
else:
pass
return render_template('login.html', form=form)
@auth_blueprint.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignupForm()
if form.validate_on_submit():
if User.query.filter_by(email=form.email.data).first():
flash('Email has been registered already!')
redirect(url_for('auth.signup'))
elif User.query.filter_by(username=form.username.data).first():
flash('Username has been registered already!')
redirect(url_for('auth.signup'))
else:
user = User(email=form.email.data,
username=form.username.data,
password=form.password.data)
db.session.add(user)
db.session.commit()
flash('Now You can login!')
return redirect(url_for('auth.login'))
return render_template('signup.html', form=form)
flash () est reçu comme suit.
example.html
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
Vous souhaiterez peut-être modifier l'affichage avant et après l'état de connexion. Par exemple, lorsque vous vous connectez, un bouton de déconnexion s'affiche.
Dans ce cas, vous pouvez utiliser current_user.is_authenticated
pour le branchement conditionnel.
example.html
{% if current_user.is_authenticated %}
<a class="nav-item nav-link" href="#">{{ current_user.username }}</a>
<a class="nav-item nav-link" href="{{ url_for('task.scheduletoday') }}">Horaire du jour</a>
<a class="nav-item nav-link" href="{{ url_for('task.alltasks')}}">Liste de tâches</a>
<a class="nav-item nav-link" href="{{ url_for('auth.logout') }}">Se déconnecter</a>
{% else %}
<a class="nav-item nav-link" href="{{ url_for('auth.login') }}">S'identifier</a>
{% endif %}
Vous pouvez le faire comme ça.
Si vous essayez d'accéder à un emplacement qui nécessite une connexion sans vous connecter, vous pouvez le limiter tant que @ login_required
est écrit, mais vous pourrez accéder à un emplacement qui ne nécessite pas de connexion lorsque vous êtes connecté. Si cela est possible, vous serez dans une situation incertaine où vous pourrez vous reconnecter même si vous êtes connecté. Dans ce cas
render_template('home.html')
ne pas
return redirect(url_for('somewhere')) if current_user.is_authenticated else render_template('home.html')
Vous pouvez le faire comme ça.
Une fois que vous avez défini une nouvelle table, vous devez la mettre à jour pour qu'elle prenne effet.
---------------------------------------
MACOS/Linux
$ export FLASK_APP=main.py
Windows
$ set FLASK_APP=main.py
flask db init
#Seulement le premier jusqu'à présent
----------------------------------------
flask db migrate -m "message"
flask db upgrade
Vous pouvez le faire comme ça.
python main.py
J'ai résumé le code que j'ai écrit jusqu'à présent et qui peut être réutilisé. Si vous avez une meilleure façon de l'écrire, faites-le nous savoir.