[Flask] Customizando Views e Models do Flask-Security

Como vimos anteriormente, as views padrões do Flask Security, são bem básicas e não tem qualquer customização de CSS e afins.

Nesse post pretendo demonstrar como customizar as views e adicionar mais informações ao model User.

Iremos utilizar o código  já feito na postagem anterior Autenticação de usuário com Flask-Security e dar sequência somente nas modificações. Caso queira baixar basta acessar o repositório criado para postagem anterior.

No arquivo models.py vamos alterar o model original de usuário, colocando um campo para o nome.

from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, \
    UserMixin, RoleMixin, login_required

from database import db

roles_users = db.Table('roles_users',
        db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
        db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))

class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)    
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    name = db.Column(db.String(255))
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

Se fizer simplesmente isso, pode perceber que a pagina de registro não reflete com o novo campo adicionado. Para que o novo campo apareça no form precisamos modificar o form de registro. Felizmente para todos os forms que pertencem ao Flask-Security foi criado uma maneira de sobrescrever o form.

Então criamos o arquivo chamado security_forms.py e nele adicionamos o seguinte codigo:

from flask_security.forms import RegisterForm, StringField, Required

class ExtendedRegisterForm(RegisterForm):
    name = StringField('Name', [Required('Name not provided')])    

No arquivo app.py vamos fazer uma pequena alteração, e ele irá ficar assim:

from flask import Flask
from database import db
from models import User, Role
from flask_security import Security, SQLAlchemyUserDatastore
#Importar a customizacao do Register Form
from  security_forms import ExtendedRegisterForm

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'super-secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'

app.config['SECURITY_SEND_REGISTER_EMAIL'] = False

app.config['SECURITY_REGISTERABLE'] = True

db.init_app(app)
user_datastore = SQLAlchemyUserDatastore(db, User, Role)

#Mudamos a linha abaixo e passamos um novo parâmetro o register_form, 
# que recebe o tipo que acabamos de declarar no arquivo security_forms.py
security = Security(app, user_datastore, register_form=ExtendedRegisterForm)

if __name__ == "__main__":
    with app.app_context():
        db.create_all()

    app.run(host="0.0.0.0", debug=True, port=8080)

Feito isso, a nossa tela de registro ainda não reflete a modificação, agora temos que criar uma nova view, para isso vamos criar as seguintes pastas dentro do projeto templates/security

Por padrão o Flask-Security verifica nessa pasta antes de carregar a view padrão. Agora é necessário criar um arquivo dentro do diretório security chamado register_user.html.

{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}
<h1>Register</h1>
&nbsp;

<form action="{{ url_for_security('register') }}" method="POST" name="register_user_form">
 {{ register_user_form.hidden_tag() }} 
 {{ render_field_with_errors(register_user_form.name) }} 
 {{ render_field_with_errors(register_user_form.email) }} 
 {{ render_field_with_errors(register_user_form.password) }} 
 {% if register_user_form.password_confirm %} 
   {{ render_field_with_errors(register_user_form.password_confirm) }} 
 {% endif %} 
 {{ render_field(register_user_form.submit) }}
</form>{% include "security/_menu.html" %}

Basicamente o que eu fiz, foi pegar a view padrão e adicionar o campo “Name”, caso queira as outras views padrões sugiro o git do Flask-Security ou você pode encontrar também na pasta de instalação do package do Flask-Security.

Agora sim, o nosso form de registro finalmente reflete o model do  usuário, porem ainda continua com a aparência ruim.

register-with-name

 

Importando o bootstrap e passando um parâmetro adicional chamado “class” para a função render_field_with_errors, temos o seguinte resultado:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flask-Security Autenticação usuário</title>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}


<div class="container">
 <div class="row">
 <div class="col-md-offset-4 col-md-4">
 <div class="login-panel panel panel-default">
 <div class="panel-heading">
 Register
 </div>
 <div class="panel-body">
 <form action="{{ url_for_security('register') }}" method="POST" name="register_user_form">
 {{ register_user_form.hidden_tag() }}
 <div class="form-group"> 
 {{ render_field_with_errors(register_user_form.name , class='form-control') }} 
 </div>
 <div class="form-group"> 
 {{ render_field_with_errors(register_user_form.email, class='form-control') }}
 </div>
 <div class="form-group"> 
 {{ render_field_with_errors(register_user_form.password, class='form-control') }}
 </div>
 <div class="form-group"> 
 {% if register_user_form.password_confirm %}
 {{ render_field_with_errors(register_user_form.password_confirm, class='form-control') }}
 {% endif %}
 </div>
 <div class="form-group"> 
 {{ render_field_with_errors(register_user_form.password, class='form-control') }}
 </div>
 <div class="form-group"> 
 {{ render_field(register_user_form.submit, class='btn btn-primary') }}
 </div>
 </form>
 </div>
 </div>
 </div>
 </div>
</div>
 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</body>
</html>

Como pode ver, ficou muito melhor e totalmente funcional.

register-formatado

Bom espero que tenha ajudo, e qualquer dúvida não tenha medo de perguntar 😉

Caso queira o código fonte, basta clicar aqui

 

 

Comecei a programar com 15 anos de idade e nunca mais parei.
Programador C# profissionalmente, e Python por opção.
%d blogueiros gostam disto: