1

我在使用 Flask、Flask-sqlalchemy 和 flask-marshmallow 创建多对多 postgresql 数据库表的条目时遇到问题。以下是我的模型设置。

role_permissions = db.Table(
    'role_permissions',
    db.Column('id', db.Integer, primary_key=True, autoincrement=True),
    db.Column('role_id', db.Integer, db.ForeignKey(
         'roles.id', ondelete='RESTRICT', onupdate='CASCADE')),
    db.Column('permission_id', db.Integer,
          db.ForeignKey('op_permission.id', ondelete='RESTRICT', onupdate='CASCADE')))

以下是各个表:角色和权限

class Role(db.Model):
    __tablename__ = 'roles'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(50), unique=True, nullable=False)
    description = db.Column(db.String(100), nullable=True)
    created_at = db.Column(db.DateTime, server_default=db.func.now())
    updated_at = db.Column(db.DateTime, server_default=db.func.now(),
                           server_onupdate=db.func.now())

    permissions = db.relationship(
        "Permission", secondary=role_permissions, backref=db.backref('roles', lazy='joined'))

    def __repr__(self):
        return '<Role {}>'.format(self.name)

    def has_id(self, id: int) -> bool:
        if Role.query.filter_by(id=id).count():
            return True
        return False

    def has_name(self, name: str) -> bool:
        if Role.query.filter_by(name=name).count():
            return True
        return False

class Permission(db.Model):
    """
    Model for permission such as GetWallet
    a combination of Action and Service
    """
    __tablename__ = 'op_permission'

    id = db.Column(db.Integer(), primary_key=True, autoincrement=True)

    service_id = db.Column(db.Integer(),
                           db.ForeignKey('op_service.id', ondelete='CASCADE'),
                           nullable=True)
    service = db.relationship(Service)

    action = db.Column(db.String(128), nullable=False, unique=True)

现在,当我尝试使用这个棉花糖模式和下面的视图向一个角色添加一组权限时(例如,我已经有一个管理员角色)

class RolePermissionsAPIView(FlaskView):
    route_base = 'iam/roles/<id>/permissions'

    """ Assign permissions to roles """

    def post(self, id, **kwargs):
        try:
            role = Role.query.filter_by(id=id).first_or_404()

            post_data = request.get_json()
            role_perm = RolePermissionsCreateSchema(partial=True).load(post_data)

            db.session.add(role_perm)
            db.session.commit()

            # also tried this
            #role.permissions.append(role_perm.permissions)
            #db.session.add(role)
            #db.session.commit()

            return jsonify(data=RoleSchema().dump(role), status=True), 201
        except NotFound:
            raise CustomException(
                message="Role does not exist", status_code=400)
        except marshmallow.exceptions.ValidationError as e:
            raise CustomException(
                message=dict(errors=e.messages), status_code=400)

对于反序列化的架构,我想传入一个现有权限 ID 列表以立即附加到一个角色。

class RolePermissionsCreateSchema(ma.ModelSchema):
    permissions = fields.Pluck('PermissionListSchema', 'id', many=True)

    class Meta:
        model = Role

这是我在传递此数据时遇到的 422 Unprocessable entity 错误。

{
    "id": 2,
    "permissions": [1, 2]
}

我用谷歌搜索无济于事。可以和 psycopg2 一起使用吗?

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python3.7/site-packages/flask_classful.py", line 268, in proxy
    response = view(**request.view_args)
  File "/usr/local/lib/python3.7/site-packages/flask_classful.py", line 239, in inner
    return fn(*args, **kwargs)
  File "/usr/src/app/users/api/v2/roles.py", line 82, in post
    db.session.commit()
  File "<string>", line 2, in commit
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1428, in commit
    self._transaction.commit(_to_root=self.future)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 829, in commit
    self._prepare_impl()
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 808, in _prepare_impl
    self.session.flush()
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 3340, in flush
    self._flush(objects)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 3480, in _flush
    transaction.rollback(_capture_exception=True)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 72, in __exit__
    with_traceback=exc_tb,
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 3440, in _flush
    flush_context.execute()
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/unitofwork.py", line 456, in execute
    rec.execute(self)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/unitofwork.py", line 579, in execute
    self.dependency_processor.process_saves(uow, states)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/dependency.py", line 1183, in process_saves
    uowcommit, secondary_insert, secondary_update, secondary_delete
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/dependency.py", line 1245, in _run_crud
    connection.execute(statement, secondary_insert)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1286, in execute
    return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 326, in _execute_on_connection
    self, multiparams, params, execution_options
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1488, in _execute_clauseelement
    cache_hit=cache_hit,
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1843, in _execute_context
    e, statement, parameters, cursor, context
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 2027, in _handle_dbapi_exception
    util.raise_(exc_info[1], with_traceback=exc_info[2])
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1780, in _execute_context
    cursor, statement, parameters, context
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/dialects/postgresql/psycopg2.py", line 957, in do_executemany
    **kwargs
TypeError: execute_values() got an unexpected keyword argument 'fetch'

将不胜感激任何帮助。

4

0 回答 0