2

Have been following Flask Security protocols for user registration and login form for flask blog-post type app, using ORM peewee. Login works like a charm though registration is posing issue. Related Question How to use Flask-Security register view?

The App:

from flask import render_template, request, redirect, url_for
from models import *
@app.route('/')
def home():
    return render_template('home.html', 
posts=Post.select().order_by(Post.date.desc()))

@app.route('/login', methods=['GET', 'POST'])
def login():
    return render_template('/security/login_user.html')


@app.route('/register', methods=['GET', 'POST'])
def register():
    return render_template('/security/register_user.html')

Database Handler:

from flask import Flask
from flask_peewee.db import Database
from peewee import *
from flask_security import Security, PeeweeUserDatastore, UserMixin, 
RoleMixin, login_required
import datetime

# Create app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret'
app.config['DATABASE'] = {
    'name': 'unnamed.db',
    'engine': 'peewee.SqliteDatabase',
}
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_REGISTER_URL'] = '/register'
app.config['SECURITY_LOGIN_USER_TEMPLATE'] = 'security/login_user.html'
app.config['SECURITY_REGISTER_USER_TEMPLATE'] = 
'security/register_user.html'
app.config['SECURITY_RESET_PASSWORD_TEMPLATE'] = 
'security/reset_password.html'
app.config['SECURITY_CHANGE_PASSWORD_TEMPLATE'] = 
'security/change_password.html'

# Database connection object
db = Database(app)

user_datastore = PeeweeUserDatastore(db, User, Role, UserRoles)
security = Security(app, user_datastore)

Register User Form (The usual Flask_Security file taken from its git):

{% from "security/_macros.html" import render_field_with_errors, 
render_field %}
{% include "security/_messages.html" %}
<h1>{{ ('Register') }}</h1>
<form action="{{ url_for_security('register') }}" method="POST" 
name="register_user_form">
  {{ register_user_form.hidden_tag() }}
  {{ 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" %}

The logs show the output during rendering as:

  • 127.0.0.1 - - [28/Apr/2017 22:07:51] "GET /login HTTP/1.1" 200 -
  • 127.0.0.1 - - [28/Apr/2017 22:07:55] "GET /register/ HTTP/1.1" 404 -

URL with backspace for register is being rendered contrasted against the login. Have checked the whole thing for some hours now, but to no avail. Any hint what might be happening?

Community
  • 1
  • 1
Manganese
  • 650
  • 5
  • 26
  • To clarify, as mentioned in the answers to the related question referenced in the post, I did check whether security.registerable was set as True, and there are no typos, plus whether security has itself been inited. But nothing till now. – Manganese Apr 28 '17 at 17:04

2 Answers2

3

Instead of:

@app.route('/register', methods=['GET', 'POST'])

You need:

@app.route('/register/', methods=['GET', 'POST'])

Note the trailing slash / at the end of '/register/'

From the Flask documentation:

If "(...) the URL is defined without a trailing slash, rather like the pathname of a file on UNIX-like systems. Accessing the URL with a trailing slash will produce a 404 “Not Found” error".

Renato Byrro
  • 3,578
  • 19
  • 34
  • Hi Renato, thanks. But that is not the problem. I tried with both variations. Additionally, if that'd have been an issue, it would have occurred when using @app.route('/login', methods=['GET', 'POST']) as well. But login works fine. – Manganese Apr 28 '17 at 20:06
  • 1
    `Login` works fine because you requested without a trailing slash: `"GET /login"`. If you request it in the browser with a trailing slash it will fail with a 404 as well. With `register` you're trying to load with a trailing slash, but the router is not configured to accept requests like that. See your logs: `"GET /register/"` – Renato Byrro Apr 28 '17 at 20:38
  • Wow! You know what, it appears that it's a browser issue. Chrome is somehow redirecting to include the trailing slash whereas as soon as I tried on Safari, '/register' works. Your point is well-taken and understood but I tried all variations before posting the question. I am absolutely not sure how browser can affect this. – Manganese Apr 28 '17 at 20:43
  • Update: It's a cache problem. I was under the assumption that Hard Refresh: hitting Ctrl+Reload in Chrome clears the cache, but apparently not. I just cleared the cache by going into the settings and everything is working like a charm. Thanks man. – Manganese Apr 28 '17 at 20:48
  • 1
    Good to know you worked it out, @Manganese. Nevertheless, it's good practice to add a trailing slash in all your routes, unless you want it to work only **without** trailing slashes, for any particular reason. – Renato Byrro Apr 28 '17 at 23:46
1

In addition to the posted resolution of including trailing slash while creating url requests- which is necessary to do as per Flask Doc, the problem above was caused due to cache not being cleared. Related question would give more insight into clearing cache with hard reload. Or, simply disable the cache when in dev mode.

Manganese
  • 650
  • 5
  • 26