Flask-sqlalchemy:无法将属性字段作为关键字参数传递给构造函数

1 投票
1 回答
2153 浏览
提问于 2025-04-18 13:24

我正在阅读《Flask Web Development》这本书,并且在创建一个类似于flasky的应用程序(可以查看这个链接:https://github.com/miguelgrinberg/flasky)。我已经设置了一个用户模型:

from flask_login import UserMixin
from werkzeug.security import check_password_hash, generate_password_hash

from app import db


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)
    password_hash = db.Column(db.String)

    @property
    def password(self):
        raise AttributeError('password is read-only')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return verify_password_hash(self.password_hash, password)

    def __init__(self, username, email):
        self.username = username
        self.email = email

现在在注册视图中,我做了:

user = User(email=form.email.data, username=form.username.data,
                password = form.password.data)

然后我遇到了以下错误:

TypeError: __init__() got an unexpected keyword argument 'password'

奇怪的是,教程项目也做了同样的事情,看看这个链接:https://github.com/miguelgrinberg/flasky/blob/master/app/auth/views.py,在第54行。

当我这样做的时候,它是可以工作的:

user = User(email=form.email.data, username=form.username.data)
user.password = form.password.data

但是我希望能够把密码传递给构造函数。显然,flask_sqlalchemy并不理解密码是一个属性。但为什么在教程中这样做就可以呢?我找不到其中的区别。

1 个回答

3

你重写了 __init__ 方法,但没有考虑到密码的问题:

def __init__(self, username, email):
    self.username = username
    self.email = email

其实不需要重写 __init__ 方法,因为默认的 SQLAlchemy 模型已经提供了一个可以接受所有字段的方法。只要删除 __init__ 的定义,事情就会 正常运作

在这本书的 代码 中,Michael 确实重写了 __init__ 方法,但他接受了所有的关键字参数,并且他做的第一件事就是把这些参数传递给父类的构造函数(这样可以保留 SQLAlchemy 的默认行为)。

撰写回答