Flask-Security用户注册信号在Python 3.3中未收到,但在2.7中有效

12

我试图使用user_registered信号来设置用户的默认角色,当他们使用Flask-Security注册时,如以下链接所示:在Flask Security中设置默认角色

我发现在我的搜索中,有一个已经解决了的bug,用于在Flask-Security中设置默认角色:Flask-Security未收到信号修复-user_registered信号问题

我尝试了以下内容,以证明处理程序是否接收到信号,但没有成功:

@user_registered.connect_via(app)
def user_registered_sighandler(sender, **extra):
    print("print-user_registered_sighandler:", extra)

即使用户注册并应该发送信号,但这部分代码从未被调用。

如果有帮助的话,我已将Flask-Security配置设置如下:

app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_CONFIRMABLE'] = False
app.config['SECURITY_SEND_REGISTER_EMAIL'] = False
app.config['SECURITY_CHANGEABLE'] = True
app.config['SECURITY_SEND_PASSWORD_CHANGE_EMAIL'] = False

Flask-Login 和 Flask-Principal 的信号对我有用,我成功地确认了以下代码片段在发送信号时可以成功打印:

@user_logged_out.connect_via(app)
def on_user_logged_out(sender, user):
    print('USER LOG OUT: made it in',user)

@identity_changed.connect_via(app)
def identity_changed_ok(sender,identity):
    print('Identity changed:',identity)

对于我的设置,我正在使用Python 3.3(Anaconda),并使用以下内容: Flask==0.10.1,flask-login==0.2.11,flask-principal==0.4.0,flask-security==1.7.4,blinker==1.3。在查看了flask-login和flask-security中的信号后,我不确定为什么flask-security的信号无法工作。
编辑: 如果我在应用程序的路由中添加print(user_registered.receivers),它将显示我有一个接收器:{139923381372400:<function user_registered_sighandler at 0x7f42737145f0>}。如果我将这个相同的打印语句放在registerable.py文件中,在user_registered.send(app._get_current_object(),user=user, confirm_token=token)之前,它会列出没有接收器:{}。
编辑2: 问题似乎与使用Python 3.3有关。 我创建了一个Python 2.7环境,并且user_registered代码按预期工作。
可用于复制的完整代码:
from flask import Flask,render_template
from playhouse.flask_utils import FlaskDB
import os
from flask.ext.security import Security, PeeweeUserDatastore
from flask.ext.security.signals import user_registered
from flask.ext.login import user_logged_out
from peewee import *
from playhouse.signals import Model
from flask.ext.security import UserMixin,RoleMixin

app = Flask(__name__)

app.config['ADMIN_PASSWORD']='secret'
app.config['APP_DIR']=os.path.dirname(os.path.realpath(__file__))
app.config['DATABASE']='sqliteext:///%s' % os.path.join(app.config['APP_DIR'], 'blog.db')
app.config['SECRET_KEY'] = 'shhh, secret!'
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_CONFIRMABLE'] = False
app.config['SECURITY_SEND_REGISTER_EMAIL'] = False

flask_db = FlaskDB()
flask_db.init_app(app)
database = flask_db.database

class BaseModel(Model):
    class Meta:
        database=flask_db.database


class User(BaseModel, UserMixin):
    email=CharField()
    password=CharField()
    active = BooleanField(default=True)
    confirmed_at = DateTimeField(null=True)

    def is_active(self):
        return True

    def is_anonymous(self):
        return False

    def is_authenticated(self):
        return True


class Role(BaseModel, RoleMixin):
    name = CharField(unique=True)
    description = TextField(null=True)


class UserRoles(BaseModel):
    user = ForeignKeyField(User, related_name='roles')
    role = ForeignKeyField(Role, related_name='users')
    name = property(lambda self: self.role.name)
    description = property(lambda self: self.role.description)


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

@user_registered.connect_via(app)
def user_registered_sighandler(sender,**extra):
    print("print-user_registered_sighandler")

@user_logged_out.connect_via(app)
def on_user_logged_out(sender, user):
    print('USER LOG OUT: made it in',user)

@app.route('/')
def index():
    print(user_registered.receivers)
    return render_template('base.html')

database.create_tables([User,Role,UserRoles], safe=True)
app.run(debug=True)

base.html 模板:

<!doctype html>
<html>
  <head>
    <title>Blog</title>
  </head>
  <body>
          <ul>
            {% if current_user.is_authenticated() %}
              <li><a href="{{ url_for('security.logout',next='/') }}">Log out</a></li>
              <li><a href="{{ url_for('security.register') }}">Register</a></li>
        {% else %}
        <li><a href="{{ url_for('security.login',next='/') }}">Login</a></li>
        <li><a href="{{ url_for('security.register') }}">Register</a></li>
            {% endif %}
            {% block extra_header %}{% endblock %}
          </ul>
  </body>
</html>
2个回答

0
如果将user_registered的导入更改为以下内容:
from flask.ext.security import user_registered

然后在 Python 3.3 中,该信号将按预期工作,并在用户注册时调用 user_registered_sighandler 函数。

user_registered 信号被导入到 flask-security 的 __init__.py 文件中,因此它也可以在包的顶层使用。


更新:现在是 from flask_security import user_registered - Rob Grant

0

我可以用类似以下的方式来实现:

security = Security(app, user_datastore,
         register_form=ExtendedRegisterForm)


@user_registered.connect_via(app)
def user_registered_sighandler(app, user, confirm_token):
    default_role = user_datastore.find_role("Pending")
    user_datastore.add_role_to_user(user, default_role)
    db.session.commit()

感谢@BrandonRose的回答。然而,这并没有解决我的问题。您使用的Python版本和相关模块是什么?即使我添加了扩展注册表单并使用您使用的函数参数,我的函数也不会被调用。 - khammel
2.7,回顾一下代码,我实际上没有看到你在哪里定义默认角色。如果在2.7中可以工作,你可以使用2.7来运行应用程序吗?如果您使用supervisord,即使您正在运行其他任务的Python 3,也可以为应用程序指定pythonpath。 - brandomr
定义默认角色不是我的问题。问题是/仍然是信号从未被接收到。我一直在使用 Peewee playhouse 信号作为解决方法。 - khammel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接