gpt4 book ai didi

Why does a redirect function outside of flask in a route like /register not redirect if I call the function?(如果我调用重定向函数,为什么/REGISTER之类的路由中的flASK外部的重定向函数不能重定向?)

转载 作者:bug小助手 更新时间:2023-10-24 22:49:01 25 4
gpt4 key购买 nike



I have 2 functions check_if_username_not_in_db and check_if_email_not_in_db that are not redirecting in the register route causing an non unique constraint in the db.

我有两个函数check_if_username_not_in_db和check_if_mail_not_in_db,它们不会在注册路由中重定向,从而导致数据库中的非唯一约束。


I managed to get the code working in the register route if I put the code below,

如果我把代码放在下面,我设法让代码在注册路径中工作,


if check_username != None or check_email != None:` 
`return render_template('register.html',title='register', form=form)` right

after check_if_username_not_in_db and check_if_email_not_in_db.

在CHECK_IF_USERNAME_NOT_IN_db和CHECK_IF_Email_NOT_IN_db之后。


I tested the code in pytest and it works so I have no idea why it needs the extra code.
Could someone please explain why?

我在PYTEST中测试了代码,它可以工作,所以我不知道为什么它需要额外的代码。有人能解释一下为什么吗?


flaskapp/app.py

Flaskapp/app.py


from flask import Flask

app = Flask(__name__)

import os
basedir_for_database = os.path.abspath(os.path.dirname(__file__))

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir_for_database, 'app.db')
app.config['SQLAlCHEMY_TRACK_mODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'zzzzzzzzzz'

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)


from flask_login import UserMixin


class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
hashed_password = db.Column(db.String(128))


# Register forms
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField

from wtforms.validators import DataRequired, Length

class RegistrationForm(FlaskForm):
'''
This is in /register route.
The forms are username, email, password and confirm_password
'''

username = StringField('Username',validators=
[
DataRequired(message='Username is required'),
Length(min=2, max=25 , message='Must be between 2 and 25 characters'),
])

email = StringField('Email', validators=
[
DataRequired('Email is required'),
Length(min=4, max=35, message='Must be between 4 and 25 characters'),
])


password = PasswordField('Password', validators=
[
DataRequired('Password is required'),
Length(min=8, max=25, message='Must be between 8 and 25 characters'),
])

confirm_password = PasswordField('Repeat Password', validators=
[
DataRequired('Does not match password'),
])
submit = SubmitField('Submit')






import bcrypt



@app.route("/", methods = ['GET'])
@app.route("/home", methods = ['GET'])
def home():
return render_template('home.html', title='home')



from flask import flash, redirect, url_for, render_template


def check_if_username_not_in_db(username_form):
'''
if the username is not in the db the code works,
if not it redirects.
This runs in the /register route.
'''

if User.query.filter_by(username=username_form).first():
flash('The username is already taken. Please select another username for registration.') # okay wording?
return redirect(url_for('register'))
else:
flash('Success the username is not taken and you can successfully register.')
return None


def check_if_email_not_in_db(email_form):
'''
if the email is not in the db the code works,
if not it redirects.
This runs in the /register route.
'''
if User.query.filter_by(email=email_form).first():
flash('The email is already taken. Please select another username for registration.') # okay wording?
return redirect(url_for('register'))
else:
flash('Success the email is not taken and you can successfully register.')
return None


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

form = RegistrationForm()
# form.validate_on_submit(): are always the same line of render template to always allow a get request.
if form.validate_on_submit():

username_form = form.username.data
email_form = form.email.data
#plaintext_password_form = form.password.data
#confirm_plaintext_password_form = form.confirm_password.data

#compare_registration_password_fields(plaintext_password_form, confirm_plaintext_password_form)
# Don't check passwords for security reasons.

# check_if_user_already_added
check_if_username_not_in_db(username_form) # why not redirects
check_if_email_not_in_db(email_form) # why not redirects





# For quicker registration comment while testing

#make_password_contain_capital(plaintext_password_form)
#make_password_contain_number(plaintext_password_form:
#make_password_contain_special_characters(plaintext_password_form)

# example password
plaintext_password = form.password.data
# converting password to array of bytes
bytes = plaintext_password.encode('utf-8')
# generating the salt
salt = bcrypt.gensalt()
# Hashing the password
hashed_password_form = bcrypt.hashpw(bytes, salt)
# Use this code if adding code to the database the first time.
add_user = User(username=username_form, email=email_form, hashed_password=hashed_password_form)
db.session.add(add_user)
db.session.commit()


# db_user = User.query.filter_by(email=email_form).first()
flash('You have almost registered successfully. Please click the link in your email to complete the registeration.')
# This is in the code in a different blueprint or in this example a different part in the file
# send_account_registration_email(db_user)


return redirect(url_for('home'))
return render_template('register.html',title='register', form=form)

if __name__ == '__main__':
app.run(debug=True)



flaskapp/templates/register.html

Flaskapp/Templates/Register.html


{%extends "layout.html"%}
<!--get the error message from wtf forms -->
{% from "_formhelpers.html" import render_field %}

{% block title %} {{title}} {% endblock title %}
{%block content%}
<!-- Once you get the error message from ( "_formhelpers.html" import render_field) , you use novalidate to
get the error message from wtf forms and makes it show up on the screen. %}
validate makes sure you have the correct route most of the time you can just leave it blank.
-->
<form validate ="" id="register" method="POST">
<!-- Make the secret key work -->
{{ form.csrf_token }}
<!--the "render_field" puts -->
{{ render_field(form.username) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm_password) }}
<input type="submit" value="Submit">
</form>


<!--make flash message work-->
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<p1> {{message}} </p1>
{% endfor %}
</ul>
{% endif %}
{% endwith %}

{%endblock content%}







flaskapp/templates/layout.html

Flaskapp/模板/layout.html



!DOCTYPE html>
<html>
<head>
{% if title %}
<title> flashblog {{+ title}} </title>
<!-- The title will say home -->
{% else %}
{{ 'home' }}
{% endif %}
</head>
<body>


{% block content %}

{% endblock content %}

</body>
</html>


flaskapp/templates/home.html

Flaskapp/Templates/home.html


{%extends "layout.html"%}



{% block content %}

{% block title %} {{title}} {% endblock title %}

<h1> Home page <h1/>


{% endblock content %}

flaskapp/templates/_formhelpers.html

Flaskapp/模板/_formhelpers.html


{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}

更多回答

Your functions for testing whether the username or email already exist return either redirect or none as the return value. Since you do not use this return value in your endpoint and return it to the client using return, the redirect will not be executed either.

您的用于测试用户名或电子邮件是否已经存在的函数返回REDIRECT或NONE作为返回值。由于您没有在端点中使用此返回值,并使用Return将其返回给客户端,因此也不会执行重定向。

@Detlef Why does it not redirect right away? If I didn't use a function it would redirect right away. Or am I wrong? Sorry for the edits.

@Detlef为什么不立即重定向?如果我不使用函数,它会立即重定向。还是我说错了?对我的编辑表示歉意。

When a defined function is called, a value is returned and can be used as a result of the call. When you visit the route, your end point will be executed. The return value of this function corresponds to the result that the client receives. A redirect corresponds to an HTTP status and a location header containing the URL. The browser then calls up the URL mentioned. If you call another function within your endpoint that may return a redirect, you have to check whether this is the case and if so, then return it again. The client only responds to the return value of the outermost function.

调用已定义的函数时,将返回一个值,并可将其用作调用的结果。当您访问该路线时,您的终点将被执行。此函数的返回值与客户端接收的结果相对应。重定向对应于包含URL的HTTP状态和Location标头。然后,浏览器调用所提到的URL。如果在端点内调用另一个可能返回重定向的函数,则必须检查是否属于这种情况,如果是,则再次返回该函数。客户端只响应最外层函数的返回值。

Sorry for the dumb question but why is the outer function only called I think you tried to explain. I am just not getting why.

对于这个愚蠢的问题,很抱歉,但是为什么只调用外部函数,我想您试图解释一下。我只是不明白为什么。

In your example, both the outer and inner functions are called. The outer function is called based on the URL mapping. You call the inner function yourself with check_if_*_not_in_db(*_form). However, in Python, indentation limits the scope of variables. A return statement is a way to pass a value between the scopes. When you make a nested function call, you can only pass the return value to the enclosing scope, but not beyond it. If you want to return the value even further, another 'return' statement is necessary to reach the next scope. This is missing for you to carry out the forwarding.

在您的示例中,外部函数和内部函数都被调用。外部函数基于URL映射进行调用。您可以使用check_if_*_not_in_db(*_form)自己调用内部函数。然而,在Python中,缩进限制了变量的作用域。Return语句是在作用域之间传递值的一种方式。进行嵌套函数调用时,只能将返回值传递到封闭的作用域,而不能超出它。如果您想进一步返回值,则需要另一个‘Return’语句才能到达下一个作用域。这是丢失的,您无法执行转发。

优秀答案推荐

So that your return value from the function to validate the user name is not lost, the result of the function must be checked again for None and otherwise returned again. Only then will the value be returned by the register function and reach the client.

为了不丢失用于验证用户名的函数的返回值,必须再次检查函数的结果是否为None,否则将再次返回。只有这样,注册函数才会返回该值并将其发送到客户端。


# This function returns either a redirect or None, 
# depending on whether the username exists.
def check_if_username_not_in_db(username_form):
# Start of the local scope of the function.

if User.query.filter_by(username=username_form).first():
flash('The username is already taken. Please select another username for registration.')

# A return statement ends the local scope and
# passes a value to the calling scope.
return redirect(url_for('register'))
else:
flash('Success the username is not taken and you can successfully register.')
return None

# Final end of the local scope of the function.

@app.route('/register', methods = ['GET', 'POST'])
def register():
# Start of the local scope of the function.

form = RegistrationForm()
if form.validate_on_submit():

# Calling the function to check the username.
# In order to execute the redirect, the return value
# must be returned again if it is not None.
# Otherwise the return value ends up being nothing.
#
# The scope of the return value of the nested function call is
# limited here by the local scope of the function.

result = check_if_username_not_in_db(form.username.data)
if result is not None:
return result

# ...

return render_template('register.html', ...)

As the example shows, outsourcing the validation of the user name and the email is not optimal due to the double check.

如示例所示,由于双重检查,将用户名和电子邮件的验证外包并不是最优的。


The following example shows you an optimized version in which the uniqueness of the user name and email is checked within the form. This has the additional advantage that the feedback to the user is displayed as part of the form field.

下面的示例显示了一个优化版本,其中在表单中检查用户名和电子邮件的唯一性。这还有一个额外的优点,即对用户的反馈显示为表单域的一部分。


'''
Install dependencies:
% pip install flask flask_bcrypt flask_login flask_sqlalchemy flask_wtf email_validator

Create the database:
% flask --app app.py shell
>> from app import db, User
>> db.create_all()

Start the application:
% flask --app app.py --debug run
'''

from flask import (
Flask,
flash,
redirect,
render_template,
request,
url_for
)
# Here flask-bcrypt is used instead of bcrypt directly.
from flask_bcrypt import Bcrypt
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import EmailField, PasswordField, StringField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, Length, ValidationError


app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY='your secret here',
# Use the instance folder as the storage location for the database.
SQLALCHEMY_DATABASE_URI='sqlite:///app.db',
SQLALCHEMY_TRACK_MODIFICATIONS=False
)
# Initializing flask-bcrypt.
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)


class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True)
username = db.Column(db.String(80), unique=True)
password_hash = db.Column(db.String(128))

# Getter for the password.
@property
def password(self):
raise AttributeError('writeonly attr: password')

# Setter for the password.
@password.setter
def password(self, value):
self.password_hash = bcrypt.generate_password_hash(value)

# Password verification.
def verify_password(self, value):
return bcrypt.check_password_hash(self.password_hash, value)


class RegistrationForm(FlaskForm):
email = EmailField('Email',
validators=[
DataRequired(),
Length(min=4, max=35),
Email()
]
)

username = StringField('Username',
validators=[
DataRequired(),
Length(min=2, max=25),
]
)

password = PasswordField('Password',
validators=[
DataRequired(),
Length(min=8, max=25),
EqualTo('password_confirm')
]
)

password_confirm = PasswordField('Repeat Password',
validators=[
DataRequired(),
]
)

submit = SubmitField('Register')

# Validation of the uniqueness of the email.
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError('The email is already taken.')

# Validation of username uniqueness.
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError('The username is already taken.')


@app.route('/')
@app.route('/home')
def index():
return render_template('index.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
# Retain inputs if inputs are incorrect.
form = RegistrationForm(request.form)
if form.validate_on_submit():
user = User()
# Transfer the form data to the user object.
form.populate_obj(user)
db.session.add(user)
db.session.commit()
flash('You have registered successfully.')
return redirect(url_for('index'))
# Pass all local variables to the template.
return render_template('register.html', **locals())

# ...

更多回答

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com