问题描述
我在人际关系方面遇到困难。我有用户和角色,并为他们定义了模型和架构。
问题是当我尝试添加一个具有先前定义的角色的新用户(我有它的 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