【问题标题】:sqlalchemy relationship select from other table instead of insertsqlalchemy 关系从其他表中选择而不是插入
【发布时间】:2021-05-16 07:09:48
【问题描述】:

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

问题是当我尝试添加具有先前定义的角色的新用户(我有其 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

然后我抓取由模式检查的用户输入并将其提交给 DB。

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

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

【问题讨论】:

  • 在您的版本中,临时对象始终用作更新现有对象或创建新对象的基础。为什么不使用 UserSchema 中的外键列而不是嵌套对象来指定角色?从这一点开始,可以从数据库中查询角色,如果不存在就做出反应。
  • @Detlef 谢谢,我想这样做,但我是 sqlalchemy 新手,不知道如何修改架构并指定外键而不是嵌套架构,您能否提供示例或任何文件?提前致谢
  • 这个平台的存在是因为有志愿者愿意牺牲自己的时间并利用他们的知识来帮助他人解决他们的问题。为了向这些人提供有关其措施成功与否的反馈,为用户提供了多种手段。如果提问者使用它来评价答案和/或将问题标记为已回答,那就太好了。即使您收到了答案,也总是可以用 cmets 澄清由此产生的任何歧义。希望您能理解我的担忧,感谢您的关注。

标签: sqlalchemy flask-sqlalchemy marshmallow flask-marshmallow marshmallow-sqlalchemy


【解决方案1】:

在我的示例中,我使用了额外的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-09
    • 2011-01-11
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多