analitics

Pages

Thursday, August 8, 2019

Python 3.7.3 : Using the flask - part 012.

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.