En el capítulo anterior, introdujimos formularios para ayudar a los usuarios a interactuar con nuestra aplicación.
En ese capítulo, cuando un usuario se registra en nuestra aplicación, su información no se guarda en una base de datos.
Para evitar ese problema, en esta sección aprenderemos a crear bases de datos y a realizar consultas
básicas para acceder a la información almacenada en nuestras bases de datos.
En este capítulo, nos centramos en el inicio de sesión y la autenticación de usuarios.
Estudiamos el paquete Flask-login y cómo podemos utilizar sus funcionalidades para permitir que el usuario inicie
sesión, cierre sesión y restrinja el acceso a algunas rutas si el usuario no está autenticado. También cambiamos el diseño de nuestra
aplicación según si el usuario está conectado o desconectado.
En esta sección, aprendemos cómo crear bases de datos en una aplicación simple. Primero, creamos una base de datos con una tabla. En segundo lugar, creamos una base de datos con dos tablas. En tercer lugar, creamos dos bases de datos, cada una con una tabla, que están conectadas.
En esta sección, aprendemos cómo crear dos bases de datos en nuestra aplicación. Primero, creamos dos bases de datos conectadas entre sí. En segundo lugar, realizamos algunas consultas y mostramos la información de esas consultas en nuestra aplicación.
Esta sección nos permite personalizar los validadores de formularios para ayudar al usuario a entender la información correcta que debe introducir en nuestra aplicación.
Esta sección estudia el paquete Flask-login y sus funcionalidades que nos permiten mejorar el inicio de sesión, cierre de sesión y otros aspectos de nuestra aplicación relacionados con la autenticación de usuarios.
Creamos más datos en nuestra base de datos y aprendemos cómo introducir más consultas para divulgar esa información.
Los enlaces a los videos de YouTube y la cuenta de GitHub para esta sección están a continuación:
Vamos a usar la línea de comandos para interactuar con nuestras bases de datos, pero también accedemos a ellas mediante una Interfaz Gráfica de Usuario. Te sugiero que descargues e instales DB Browser para SQLite o cualquier otra Interfaz Gráfica de Usuario para interactuar con nuestra base de datos. Para descargar DB Browser para SQLite, puedes usar los siguientes enlaces:
Toda la información en esta sección se ha tomado de los siguientes enlaces:
Flask-SQLAlchemy es una extensión para Flask que agrega soporte para SQLAlchemy a tu aplicación. Simplifica el uso de SQLAlchemy con Flask al configurar objetos comunes y patrones para usar esos objetos, como una sesión vinculada a cada solicitud web, modelos y motores. Flask-SQLAlchemy no cambia cómo funciona o se usa SQLAlchemy.
¿Qué es SQLAlchemy? SQLAlchemy es el kit de herramientas SQL para Python y Mapper Relacional de Objetos que otorga a los desarrolladores de aplicaciones el poder y la flexibilidad completos de SQL.
Proporciona un conjunto completo de patrones de persistencia a nivel empresarial bien conocidos, diseñados para un acceso a bases de datos eficiente y de alto rendimiento, adaptados a un lenguaje de dominio simple y Pythonico.
¿Qué es SQL? Structured Query Language, abreviado como SQL, es un lenguaje específico de dominio utilizado en programación y diseñado para gestionar datos en un sistema de gestión de bases de datos relacional, o para el procesamiento de flujos en un sistema de gestión de flujos de datos relacional.
Los enlaces al video de YouTube y a la cuenta de GitHub para esta sección están a continuación:
Comenzamos creando una aplicación simple con una base de datos con una tabla. Procedemos en cinco pasos (el código para la aplicación está en el panel derecho):
from flask_sqlalchemy import SQLAlchemy
application.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///light_talk_app.db'
db = SQLAlchemy(application)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
application = Flask(__name__)
application.config['SQLALCHEMY_DATABASE_URI'] =
'sqlite:///light_talk_app.db'
db = SQLAlchemy(application)
class User(db.Model):
__tablename__ = "user_table"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True,
nullable=False)
@application.route('/')
@application.route('/home')
def home():
return "<h1>Bienvenido a casa</h1>"
if __name__=='__main__':
application.run(debug=True)
class User(db.Model):
__tablename__ = "user_table"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True, nullable=False)
Una vez que hayamos creado nuestra base de datos, podemos comenzar a rellenarla con datos. Procedemos en los siguientes pasos:
from application import User
user1 = User(username='Bjørk')
db.session.add(user1)
user2 = User(username='Fjell')
db.session.add(user2)
db.session.commit()
También podemos realizar algunas consultas básicas.
User.query.first()
User.query.filter_by(username='Bjørk').all()
User.query.filter_by(username='Bjørk').first().username
Podemos crear variables utilizando consultas básicas.
user1 = User.query.get(1)
user1.id
user1.username
user2 = User.query.filter_by(username='Bjørk').first()
user2.id
user2.username
Los enlaces al video de YouTube y a la cuenta de GitHub para esta sección están a continuación:
Para introducir una segunda tabla en nuestra base de datos, procedemos en dos pasos diferentes (el código para la aplicación está en el panel derecho):
class Sentence(db.Model):
__tablename__= 'sentence_table'
id = db.Column(db.Integer, primary_key=True)
incorrect_sentence = db.Column(db.String)
sentence = db.relationship('Sentence', backref='author', lazy=True)
user_id = db.Column(db.Integer, db.ForeignKey('user_table.id'),
nullable=False)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
application = Flask(__name__)
application.config['SQLALCHEMY_DATABASE_URI'] =
'sqlite:///light_talk_app.db'
db = SQLAlchemy(application)
class User(db.Model):
__tablename__ = "user_table"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30),
unique=True, nullable=False)
sentence = db.relationship('Sentence',
backref='author', lazy=True)
class Sentence(db.Model):
__tablename__= 'sentence_table'
id = db.Column(db.Integer, primary_key=True)
incorrect_sentence = db.Column(db.String)
user_id = db.Column(db.Integer,
db.ForeignKey('user_table.id'), nullable=False)
@application.route('/')
@application.route('/home')
def home():
return "<h1>Bienvenido a casa</h1>"
if __name__=='__main__':
application.run(debug=True)
Una vez que hayamos creado nuestra base de datos, podemos comenzar a rellenarla con datos. Procedemos en los siguientes pasos:
from application import User, Sentence
user1 = User(username='Bjørk')
db.session.add(user1)
user2 = User(username='Fjell')
db.session.add(user2)
db.session.commit()
sentence1 = Sentence(incorrect_sentence =
"Mi perro es bonitos", user_id=user1.id)
sentence2 = Sentence(incorrect_sentence =
"Mi casa es bonito", user_id=user1.id)
db.session.add(sentence1)
db.session.add(sentence2)
sentence3 = Sentence(incorrect_sentence =
"Mis perros es grande", user_id=user2.id)
sentence4 = Sentence(incorrect_sentence =
"Mi amiga es alto", user_id=user2.id)
db.session.add(sentence3)
db.session.add(sentence4)
db.session.commit()
También podemos realizar algunas consultas básicas.
sentence1 = Sentence.query.first()
sentence1.user_id
sentence1.author
sentence1.author.username
sentence1.incorrect_sentence
db.session.add(sentence4)
db.session.commit()
Los enlaces al video de YouTube y a la cuenta de GitHub para esta sección están a continuación:
En muchos casos, estamos interesados en tener diferentes bases de datos en nuestra aplicación. Si nuestra empresa opera en diferentes países, podría ser útil tener bases de datos separadas para cada país. Si nuestra empresa tiene diferentes fábricas, también podría ser útil tener diferentes bases de datos. Aprendemos cómo crear dos bases de datos con una tabla cada una. Es muy fácil crear más bases de datos y/o tablas en cada base de datos.
Para crear dos bases de datos con dos tablas, procedemos en tres pasos (el código para la aplicación está en el panel derecho):
application.config['SQLALCHEMY_DATABASE_URI'] =
'sqlite:///user.db'
application.config['SQLALCHEMY_BINDS'] =
{'sentence': 'sqlite:///sentence.db'}
class Sentence(db.Model):
__bind_key__ = 'sentence'
__tablename__ = 'sentence_table'
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
application = Flask(__name__)
application.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///user.db'
application.config['SQLALCHEMY_BINDS'] =
{'sentence': 'sqlite:///sentence.db'}
db = SQLAlchemy(application)
class User(db.Model):
__tablename__ = "user_table"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True, nullable=False)
sentence = db.relationship('Sentence', backref='author', lazy=True)
class Sentence(db.Model):
__bind_key__ = 'sentence'
__tablename__ = 'sentence_table'
id = db.Column(db.Integer, primary_key=True)
incorrect_sentence = db.Column(db.String)
user_id = db.Column(db.Integer,
db.ForeignKey('user_table.id'), nullable=False)
@application.route('/')
@application.route('/home')
def home():
return "<h1>Bienvenido a casa</h1>"
if __name__=='__main__':
application.run(debug=True)
Los enlaces al video de YouTube y la cuenta de GitHub para esta sección están a continuación:
En esta sección, creamos dos bases de datos en nuestra aplicación, cada una con una tabla. Procedemos en cuatro pasos diferentes.
from flask_sqlalchemy import SQLAlchemy
application.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///user.db'
application.config['SQLALCHEMY_BINDS'] ={'sentence': 'sqlite:///sentence.db'}
db = SQLAlchemy(application)
from capp.models import User
from capp.models import Sentence
from capp import db
from datetime import datetime
# Base de datos Usuario
class User(db.Model):
__tablename__ = "user_table"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(30), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
sentence = db.relationship('Sentence', backref='author', //
lazy=True)
# Base de datos Sentencee
class Sentence(db.Model):
__bind_key__ = 'sentence'
__tablename__= 'sentence_table'
id = db.Column(db.Integer, primary_key=True)
incorrect_sentence = db.Column(db.String)
correct_sentence_one = db.Column(db.String)
correct_sentence_two = db.Column(db.String)
correct_sentence_three = db.Column(db.String)
correct_sentence_four = db.Column(db.String)
objective = db.Column(db.String)
source = db.Column(db.String)
user_id = db.Column(db.Integer, db.ForeignKey('user_table.id'),//
nullable=False)
En el paquete user, en el archivo routes.py, debemos introducir tres cambios (el código para la aplicación está en el panel derecho):
from capp import db, bcrypt
user_hashed_password = bcrypt.generate_password_hash//
(form.password.data).decode('utf-8')
user = User(username=form.username.data, //
email=form.email.data, password=user_hashed_password)
db.session.add(user)
db.session.commit()
from capp import db, bcrypt
@users.route('/register', methods=['GET','POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user_hashed_password = bcrypt.generate_password_hash//
(form.password.data).decode('utf-8')
user = User(username=form.username.data, //
email=form.email.data, password=user_hashed_password)
db.session.add(user)
db.session.commit()
flash('¡Tu cuenta ha sido creada! //
Ahora puedes iniciar sesión.', 'success')
return redirect(url_for('home.home_home'))
return render_template('register.html', title='Register', //
form=form)
Algunos enlaces útiles sobre consultas en SQLAlchemy se pueden encontrar en los siguientes enlaces:
En el paquete home, en el archivo routes.py, debemos introducir tres cambios.
from capp.models import User, Sentence
user1 = User.query.first().username
sentence1 = Sentence.query.first().incorrect_sentence
user3 = User.query.filter_by(username='Bjørk').first().username
user4 = User.query.filter_by(username='Bjørk').first()
sentences = Sentence.query.filter_by(user_id=user4.id)
users = User.query.all()
return render_template('home.html', user1=user1, //
sentence1=sentence1, user3=user3, sentences=sentences, users=users)
<!-- Consultas -->
<section class="section_developers">
<div class="container">
<div class="developers" style="display:block;">
<h5>Consulta 1</h5>
{{user1}}
<h5>Consulta 2</h5>
{{sentence1}}
<h5>Consulta 3</h5>
{{user3}}
<h5>Consulta 4</h5>
{% for sentence in sentences %}
{{sentence.incorrect_sentence}}
{% endfor %}
<h5>Consulta 5</h5>
{% for user in users %}
{{user.username}}
{% endfor %}
</div>
</div>
</section>
Los enlaces a los videos de YouTube y la cuenta de GitHub para esta sección están a continuación:
Toda la información en esta sección ha sido tomada de los siguientes enlaces:
Personalizamos los mensajes que se muestran al usuario. Si, por ejemplo, intentamos registrarnos usando el mismo nombre de usuario o correo electrónico, recibimos un mensaje no deseado. Para evitar esos mensajes que podrían no ser muy útiles para los usuarios de nuestra aplicación, podemos personalizar nuestros Validadores de Formularios WTF.
En el paquete users, en el archivo forms.py.
class MyForm(Form):
name = StringField('Nombre', [InputRequired()])
def validate_name(form, field):
if len(field.data) > 50:
raise ValidationError('El nombre debe tener menos de 50 caracteres')
from capp.models import User
from wtforms.validators import ValidationError
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('Ese nombre de usuario ya está en uso.//
Por favor, elige uno diferente.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('Ese correo electrónico ya está en uso. //
Por favor, elige uno diferente.')
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField,
BooleanField
from wtforms.validators import DataRequired, Length, Email,
EqualTo, ValidationError
from capp.models import User
class RegistrationForm(FlaskForm):
username = StringField('Nombre de usuario',
validators=[DataRequired(), Length(min=2, max=30)])
email = StringField('Correo electrónico',
validators=[DataRequired(), Email()])
password = PasswordField('Contraseña', validators=[DataRequired()])
confirm_password = PasswordField('Confirmar contraseña',
validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Registrarse')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('Ese nombre de usuario ya está en uso. //
Por favor, elige uno diferente.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('Ese correo electrónico ya está en uso. //
Por favor, elige uno diferente.')
Los enlaces al video de YouTube y a la cuenta de GitHub para esta sección están a continuación:
Toda la información en esta sección ha sido tomada de los siguientes enlaces:
Flask-Login proporciona la gestión de sesiones de usuario para Flask. Maneja las tareas comunes de iniciar sesión, cerrar sesión y recordar las sesiones de tus usuarios durante períodos prolongados.
Este paquete hará lo siguiente:
from flask_login import LoginManager
login_manager = LoginManager()
El login manager contiene el código que permite que tu aplicación y Flask-Login trabajen juntos, como cargar un usuario a partir de un ID, a dónde enviar a los usuarios cuando necesitan iniciar sesión, y similares.
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
Debe devolver None (no generar una excepción) si la ID no es válida. (En ese caso, la ID se eliminará manualmente de la sesión y se continuará con el procesamiento).
En esta sección, utilizamos Flask-login en nuestra aplicación. Introducimos cuatro cambios que nos permiten usar diferentes funcionalidades de Flask-login.
pip install flask-login
from flask_login import LoginManager
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
login_manager= LoginManager(application)
from capp import login_manager
from flask_login import UserMixin
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin)
from flask_login import LoginManager
login_manager= LoginManager(application)
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
from capp import login_manager
from flask_login import UserMixin
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
from capp.users.forms import RegistrationForm
from capp.models import User
from capp import db, bcrypt
from flask_login import login_user
users=Blueprint('users',__name__)
@users.route('/register', methods=['GET','POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user_hashed_password = //
bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username=form.username.data, email=form.email.data, //
password=user_hashed_password)
db.session.add(user)
db.session.commit()
flash('¡Tu cuenta ha sido creada! Ahora puedes iniciar sesión.', 'success')
return redirect(url_for('users.login'))
return render_template('users/register.html', //
title='register', form=form)
from flask_login import login_user
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
flash('¡Has iniciado sesión! Ahora puedes comenzar a usar nuestra aplicación.', 'success')
else:
flash('Inicio de sesión fallido. ¡Por favor, verifica el correo electrónico y la contraseña!', 'danger')
login_user(user, remember=form.remember.data)
En esta sección, nos enfocamos en tres usos diferentes de Flask-login que son útiles para nuestra aplicación.
from flask_login import current_user
if current_user.is_authenticated:
return redirect(url_for('home.home_home'))
from flask_login import logout_user
@users.route('/logout')
def logout():
logout_user()
return redirect(url_for('home.home_home'))
from flask_login import login_required
@light_talk_app.route('/light_talk_app')
@login_required
from flask import render_template, Blueprint, redirect, flash,
url_for, request
from capp.users.forms import RegistrationForm, LoginForm
from capp.models import User
from capp import db, bcrypt
from flask_login import login_user, current_user, logout_user
users=Blueprint('users',__name__)
@users.route('/register', methods=['GET','POST'])
def register():
...
@users.route('/login', methods=['GET','POST'])
def login():
form = LoginForm()
if current_user.is_authenticated:
return redirect(url_for('home.home_home'))
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password,
form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
flash('¡Has iniciado sesión! Ahora puedes comenzar a
usar nuestra aplicación Light Talk.', 'success')
return redirect(next_page) if next_page else
redirect(url_for('home.home_home'))
else:
flash('Inicio de sesión fallido. ¡Por favor,
verifica el correo electrónico y la contraseña!',
'danger')
return render_template('users/login.html', title='login', form=form)
@users.route('/logout')
def logout():
logout_user()
return redirect(url_for('home.home_home'))
@light_talk_app.route('/light_talk_app')
@login_required
@light_talk_app.route('/light_talk_app/nueva_frase')
@login_required
@light_talk_app.route('/light_talk_app/tus_frases')
@login_required
from flask import request
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
flash('¡Has iniciado sesión! Ahora puedes comenzar a usar nuestra aplicación Light Talk.', 'success')
return redirect(next_page) if next_page else redirect(url_for('home.home_home'))
else:
{% if current_user.is_authenticated %}
<nav>
<ul>
<li>
<a href="{{url_for('users.logout')}}">Cerrar sesión</a>
</li>
<li>
<a href="{{url_for('home.home_home')}}">Inicio</a>
</li>
<li>
<a href="{{url_for('business.business_home')}}">
Negocio</a>
</li>
<li>
<a href="{{url_for('light_talk_app.light_talk_app_home')}}">
Light-Talk-App</a>
</li>
</ul>
</nav>
{% else %}
<nav>
<ul>
<li>
<a href="{{url_for('users.register')}}">Registrarse</a>
</li>
<li>
<a href="{{url_for('users.login')}}">Iniciar sesión</a>
</li>
<li>
<a href="{{url_for('home.home_home')}}">Inicio</a>
</li>
<li>
<a href="{{url_for('business.business_home')}}">
Negocio</a>
</li>
<li>
<a href="{{url_for('light_talk_app.light_talk_app_home')}}">
Light-Talk-App</a>
</li>
</ul>
</nav>
{% endif %}
{% if current_user.is_authenticated %}
{% else %}
<div class="container_buttons_links_header_home">{
<div class="btn">
<a href="{{url_for('users.register')}}"
class="btn btn-primary btn-lg mr-2",
style="background-color:#007bff;">Registrarse</a>
</div>
<div class="btn">
<a href="{{url_for('users.login')}}"
class="btn btn-primary btn-lg mr-2",
style="background-color:#007bff;">Iniciar sesión</a>
</div>
</div>
{% endif %}
En este reto semanal, vamos a crear algunas consultas SQLAlchemy para acceder a nuestras bases de datos, y vamos a utilizar código Python para extraer información de las filas obtenidas mediante las consultas.
Nos vamos a enfocar en cinco consultas diferentes. Sin embargo, te animo a que crees tus propias consultas y experimentes con las bases de datos y el código Python. Las seis consultas que vamos a estudiar en el reto semanal son:
Sé que este reto semanal puede ser difícil, ya que vas a utilizar consultas SQLAlchemy y Python, y algunos de ustedes no están familiarizados con estos dos lenguajes de programación. Te animo a revisar el código, ejecutar la aplicación y tratar de entender la lógica detrás del código. Vamos a revisar el reto semanal juntos durante las clases.