0

我在人际关系中遇到困难。我有用户和角色,并为他们定义了模型和模式。

问题是当我尝试添加具有先前定义的角色的新用户(我有它的 ID 和名称)时,它将尝试通过用户指定的值更新/插入角色表。但我只想从角色中选择并将其指定为用户角色而不更新角色表(如果找不到角色返回错误)。

我想要实现的是如何限制 SQLalchemy 通过用户指定的值更新相关表。

这是我的模型:

class User(db.Model):
"""user model
"""
__tablename__ = 'user'
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True, nullable=False)
username = db.Column(db.String(40), unique=True, nullable=False)       
password = db.Column(db.String(255), nullable=False)
role_id = db.Column(UUID(as_uuid=True), db.ForeignKey('role.id') , nullable=False)

class Role(db.Model):
"""role model
"""
__tablename__ = 'role'
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True, nullable=False)
name = db.Column(db.String(40), unique=True, nullable=False)
perm_add = db.Column(db.Boolean, default=False)
perm_edit = db.Column(db.Boolean, default=False)
perm_del = db.Column(db.Boolean, default=False)

这是我定义的架构:

class UserSchema(ma.SQLAlchemyAutoSchema):

password = ma.String(load_only=True, required=True)
email = ma.String(required=True)
role = fields.Nested("RoleSchema", only=("id", "name"), required=True)

class Meta:
    model = User
    sqla_session = db.session
    load_instance = True

我抓取由模式检查的用户输入并将其提交给数据库。

    schema = UserSchema()
    user = schema.load(request.json)
    db.session.add(user)
    try:
      db.session.commit()

关键是在这里我无法更改有关角色名称或 ID 的任何内容,因为它似乎在应用于 DB 之前已被架构更改(我的意思是 request.json)

4

1 回答 1

0

在我的示例中,我使用了附加的webargs库。它有助于在服务器端进行验证并启用干净的符号。由于 marschmallow 无论如何都是基于 webargs 的,所以我认为添加是有道理的。
我已经根据你的规格。根据您打算进一步做的事情,您可能需要进行调整。

我向用户模型添加了一个关系,以使角色更易于使用。

class User(db.Model):
    """user model"""

    # ...

    # The role is mapped by sqlalchemy using the foreign key 
    # as an object and can be reached via a virtual relationship. 
    role = db.relationship('Role')

我已允许外键作为模式中的查询参数,并将嵌套模式限制为输出。电子邮件被分配给用户名。

class RoleSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = Role
        load_instance = True

class UserSchema(ma.SQLAlchemyAutoSchema):
    # The entry of the email is converted into a username.
    username = ma.String(required=True, data_key='email')
    password = ma.String(required=True, load_only=True)
    
    # The foreign key is only used here for loading. 
    role_id = ma.Integer(required=True, load_only=True)
    # The role is dumped with a query. 
    role = ma.Nested("RoleSchema", only=("id", "name"), dump_only=True)

    class Meta:
        model = User
        load_instance = True
        include_relationships = True

现在可以从数据库中查询角色并在它不存在时做出反应。角色的数据库表不再自动更新。

from flask import abort
from sqlalchemy.exc import SQLAlchemyError
from webargs.flaskparser import use_args, use_kwargs

# A schema-compliant input is expected as JSON 
# and passed as a parameter to the function. 
@blueprint.route('/users/', methods=['POST'])
@use_args(UserSchema(), location='json')
def user_new(user):
    # The role is queried from the database and assigned to the user object.
    # If not available, 404 Not Found is returned. 
    user_role = Role.query.get_or_404(user.role_id)
    user.role = user_role
    
    # Now the user can be added to the database. 
    db.session.add(user)
    try:
        db.session.commit()
    except SQLAlchemyError as exc:
        # If an error occurs while adding to the database, 
        # 422 Unprocessable Entity is returned 
        db.session.rollback()
        abort(422)
    
    # Upon successful completion, the new user is returned 
    # with the status code 201 Created. 
    user_schema = UserSchema()
    user_data = user_schema.dump(user)
    return jsonify(data=user_data), 201
于 2021-02-14T13:45:47.067 回答