sqlalchemy 关系从其他表中选择而不是插入

问题描述

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

问题是当我尝试添加一个具有先前定义的角色的新用户我有它的 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),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),nullable=False)
name = db.Column(db.String(40),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)

解决方法

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...