The goal of this tutorial step is to understand how the project can use the new features and implementation of the project.
Because in the last tutorial I used the
flask_mail python module, now I will add into my project structure.
One good issue is registration issue for users.
First, you need to see the full project and changes at
my GitHub project.
I used the
itsdangerous python module to use tokens.
Let's install this with the pip tool:
C:\Python373\Scripts>pip install itsdangerous
For registration is need to have login issues and we can use
LoginManager, see the
extensions.py
#use SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
#use LoginManager
from flask_login import LoginManager
#create login_manager
login_manager = LoginManager()
#create db
db = SQLAlchemy()
Let's see the new User model, see the
models.py:
#imports for user model
from datetime import datetime
from .extensions import db
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from blue_test import login_manager
from flask_login import UserMixin
# import db from base folder, see dot
from .extensions import db
#load the user by id
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# create the Texts mode
class Texts(db.Model):
# primary key
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(50))
txt_content = db.Column(db.String(1000))
# create the User model
'''
id = id key for user
username = name
email = user email
password = user password
'''
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
def get_reset_token(self, expires_sec=1800):
s = Serializer(app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
@staticmethod
def verify_reset_token(token):
s = Serializer(app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
In the
blue_test folder project I created the
templates folder with two HTML5 files:
home.html and
register.html.
I created also the
forms.py file and I update with my forms:
RegistrationForm,
RequestResetForm,
ResetPasswordForm.
#import python for create forms
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
# import python for validate forms field
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
#import python files project
from .extensions import db, login_manager
class RegistrationForm(FlaskForm):
username = StringField('Username',
validators=[DataRequired(), Length(min=2, max=25)])
email = StringField('Email',
validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is taken.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('That email is taken.')
class RequestResetForm(FlaskForm):
email = StringField('Email',
validators=[DataRequired(), Email()])
submit = SubmitField('Password Reset')
def validate_email(self, email):
#get user by email
if user is None:
raise ValidationError('There is no account with that email.')
class ResetPasswordForm(FlaskForm):
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password',
validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Reset Password')
In the
__init__.py file I add this:
#import python files project
from .extensions import db, login_manager
...
login_manager.init_app(app)
The
routers.py will have the new
RegistrationForm:
@api.route("/register", methods=['GET', 'POST'])
def register():
# check if the user is authenticated
if current_user.is_authenticated:
return redirect(url_for('home'))
form = RegistrationForm()
if form.validate_on_submit():
flash('Your account has been created!, 'success')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
Depending on your needs, we will send and redirect these forms to the HTML files.
Depending on your needs (users, page access, ...) we will be able to write the source code further.