[PYTHON] Codes, die in Flask wiederverwendet werden könnten (anmelden, anmelden)

Einführung

Ich mache eine Web-App mit Flask und habe Code, der wiederverwendet werden kann, also werde ich ihn teilen. Wir haben nicht erwähnt, welcher Code welche Funktionen bietet. Bitte recherchieren Sie selbst.

Annahme

Installation

Installieren Sie die diesmal zu verwendende Erweiterung im Voraus. Sie müssen die Version nicht angeben, da die neuesten Versionen vorbereitet werden.

requirements.txt


Flask
Flask-Login
Flask-Migrate
Flask-SQLAlchemy
Flask-WTF
SQLAlchemy
Werkzeug
WTForms
Jinja2
email-validator
pip install -r requirements.txt

Dateiorganisation

Flask verwendet so etwas wie "Blueprint", um die Funktionalität zu teilen.

├───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

In dieser Konfiguration enthält "__init __. Py" "config", Sie können es jedoch als "config.py" trennen.

Wir haben ein gemeinsames Layout für "base.html" vorbereitet und es als "{{% erweitert" base.html "%}}" unter Verwendung einer Vorlagen-Engine namens "jinja2" ("layout") wiederverwendet. Der Name hmtl` wird auch häufig verwendet).

Ich verwende "SQLite" für SQL, kann es jedoch nicht für "Heroku" bereitstellen und es ist nicht für die Skalierung geeignet. Wenn Sie also SQL verwenden, ist es besser, tatsächlich "MySQL" oder "PostgreSQL" zu verwenden. Ich denke. Da wir "ORM" mit dem Namen "SQLAlchemy" verwenden, um die Datenbank zu verwalten, kann derselbe Code verwendet werden, auch wenn SQL anders ist (das Setup ist anders). data.sqlite`` migrations ist eine von Ihnen selbst erstellte Datei / ein Ordner.

Es ist eine Anforderung von "Blueprint", eine redundante Struktur wie "myproject \ auth \ templates \ auth" zu haben.

In "auth \ forms.py" werden die Anmelde- und Anmeldeformulare empfangen, und in "auth \ views.py" werden die aus den Formularen eingegebenen Daten empfangen, verarbeitet und gerendert.

main.py und __ init __. py

Da main.py nur Anrufe tätigt, sieht es folgendermaßen aus:

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)

Diese Datei registriert sich bei config und blueprint und führt die gesamte Initialisierung durch.

__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__))

#Wenn Sie das Heroku Postgres-Add-On hinzufügen, wird die Umgebungsvariable DATABASE hinzugefügt_Zur URL
#Dieser Wert wird festgelegt, da die Verbindungsziel-URL der PostgreSQL-Datenbank festgelegt ist.
#Wenn eingestellt(Beim Laufen auf Heroku)Benutze es,
#Wenn nicht eingestellt(Lokales Debuggen usw.)Ermöglicht die Verwendung der lokalen SQLite-Datenbank.

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)

#Stellen Sie sicher, dass Sie hier importieren, nachdem Sie die Definition von db abgeschlossen haben
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"

Die letzte Zeile "login_manager.login_view =" auth.login "" bezieht sich auf den Anmeldebildschirm, der umgeleitet wird, wenn Sie versuchen, darauf zuzugreifen, obwohl "@ login_required" vorhanden ist.

Wenn Sie beispielsweise versuchen, zu "\ logout" zu wechseln, während Sie nicht angemeldet sind, wird die in "views.py" definierte Anmeldefunktion aufgerufen (da der Anmeldebildschirm durch die Rückkehr der Funktion gerendert wird, wechseln Sie zu diesem Bildschirm. Masu).

Benutzerdatenbank

Die Tabelle ist in models.py definiert. Ich behalte meinen Benutzernamen, meine E-Mail-Adresse und mein Hash-Passwort.

Abgesehen davon ist der Grund, warum die Schaltfläche "Passwort vergessen?" Das Passwort nicht anzeigt, dass es überhaupt nicht in der Datenbank verbleibt, sodass Sie es nicht sagen können.

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)

Anmeldevorgang

Es ist für die allgemeine Benutzeranmeldung vorgesehen. Der Nutzer

Geben Sie die.

Erstens ist das Anmeldeformular.

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')

Als nächstes folgt die interne Verarbeitung. Der Benutzername und die E-Mail-Adresse dürfen sich in der Datenbank nicht überschneiden. Wenn sie in der Datenbank übereinstimmen, wird ein Fehler ausgegeben und Sie werden aufgefordert, sie erneut einzugeben.

Wenn Sie sich erfolgreich angemeldet haben, werden Sie zum Anmeldeformular weitergeleitet.

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)

Anmeldevorgang

Es wird davon ausgegangen, dass sich ein allgemeiner Benutzer anmeldet.

Der Benutzer gibt eine E-Mail-Adresse und ein Passwort ein. Es wird in derselben Datei wie das Anmeldeformular beschrieben.

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')

Als nächstes folgt die interne Verarbeitung. Identifizieren Sie den Benutzer anhand der E-Mail-Adresse. Das Passwort wird mit dem Passwort-Hash-Wert des Benutzers verglichen, indem die in models.py gespielte Funktion check_password verwendet wird.

Wenn Sie sich erfolgreich angemeldet haben, können Sie zu einem beliebigen Ort springen.

Übrigens werde ich auch den Abmeldevorgang verlassen.

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 () Meldung anzeigen

flash () wird wie folgt empfangen.

example.html



{% with messages = get_flashed_messages() %}
  {% if messages %}
    {% for message in messages %}

      {{ message }}

    {% endfor %}
  {% endif %}
{% endwith %}

Ändern Sie die Anzeige vor und nach dem Anmeldestatus

Möglicherweise möchten Sie die Anzeige vor und nach dem Anmeldestatus ändern. Wenn Sie sich beispielsweise anmelden, wird eine Schaltfläche zum Abmelden angezeigt.

In diesem Fall können Sie "current_user.is_authenticated" für die bedingte Verzweigung verwenden.

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') }}">Der heutige Zeitplan</a>
    <a class="nav-item nav-link" href="{{ url_for('task.alltasks')}}">Aufgabenliste</a>
    <a class="nav-item nav-link" href="{{ url_for('auth.logout') }}">Ausloggen</a>
{% else %}
    <a class="nav-item nav-link" href="{{ url_for('auth.login') }}">Einloggen</a>
{% endif %}

Sie können es so machen.

Zugriffsbeschränkungen während der Anmeldung

Wenn Sie versuchen, auf einen Speicherort zuzugreifen, für den eine Anmeldung erforderlich ist, ohne sich anzumelden, können Sie ihn einschränken, solange "@ login_required" geschrieben ist. Sie können jedoch auf einen Speicherort zugreifen, für den während der Anmeldung keine Anmeldung erforderlich ist. Wenn dies möglich ist, befinden Sie sich in einer unsicheren Situation, in der Sie sich erneut anmelden können, obwohl Sie angemeldet sind. In einem solchen Fall

render_template('home.html')

nicht


return  redirect(url_for('somewhere')) if current_user.is_authenticated else render_template('home.html')

Sie können es so machen.

Datenbankaktualisierung

Nachdem Sie eine neue Tabelle definiert haben, müssen Sie sie aktualisieren, damit sie wirksam wird.

---------------------------------------
MACOS/Linux
    $ export FLASK_APP=main.py
Windows
    $ set FLASK_APP=main.py

flask db init

#Nur der erste bisher
----------------------------------------
flask db migrate -m "message"
flask db upgrade

Sie können es so machen.

Versuchen Sie es in der lokalen Umgebung

python main.py

abschließend

Ich habe den Code, den ich bisher geschrieben habe, zusammengefasst, der wiederverwendet werden kann. Wenn Sie eine bessere Möglichkeit haben, es zu schreiben, lassen Sie es uns bitte wissen.

Recommended Posts

Codes, die in Flask wiederverwendet werden könnten (anmelden, anmelden)
Ein Datensatz, den GAMEBOY mit Python nicht erstellen konnte. (PYBOY)
Tkinter konnte nicht in Python importiert werden