【问题标题】:Python Flask API : How to send back selective columns from the resultset of a sqlalchemy joinPython Flask API:如何从 sqlalchemy 连接的结果集中发回选择性列
【发布时间】:2018-04-17 23:24:38
【问题描述】:

我正在尝试编写一个简单的代码 sn-p 来打印 3 个表连接查询的结果。我正在使用 python/flask-restplus/sqlalchemy

这是我的例子:

class Users(db.Model):
    id = db.Column(db.Integer, db.Sequence('users_id_seq'), primary_key=True)
    email = db.Column(db.String(64), unique=True, nullable=False)
    password = db.Column(db.String(128), nullable=False)
    created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    expires = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    rights = db.relationship('Rights', backref='user', lazy=True)

    def __repr__(self):
        return '<Users %r>' % self.email

class Applications(db.Model):
    id = db.Column(db.Integer, db.Sequence('applications_id_seq'), primary_key=True)
    code = db.Column(db.String(5), unique=True, nullable=False)
    name = db.Column(db.String(128), nullable=False)
    rights = db.relationship('Rights', backref='application', lazy=True)

    def __repr__(self):
        return '<Applications %r>' % self.code

class Rights(db.Model):
    id = db.Column(db.Integer, db.Sequence('rights_id_seq'), primary_key=True)
    role = db.Column(db.String(16), nullable=False)
    app_id = db.Column(db.Integer, db.ForeignKey('applications.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

    def __repr__(self):
        return '<Rights %r>' % self.role

db.drop_all()
db.create_all()
user1 = Users(email='user1@example.com', password='password1')
user2 = Users(email='user2@example.com', password='password2')
user3 = Users(email='user3@example.com', password='password3')
appli1 = Applications(code='APP1', name='Appli 1')
appli2 = Applications(code='APP2', name='Appli 2')
appli3 = Applications(code='APP3', name='Appli 3')
db.session.add(user1)
db.session.add(user2)
db.session.add(user3)
db.session.add(appli1)
db.session.add(appli2)
db.session.add(appli3)

u1=Users.query.get(1)
a1=Applications.query.get(1)
rights1 = Rights(role='MANAGER', application=a1, user=u1)
db.session.add(rights1)

a2=Applications.query.get(2)
rights2 = Rights(role='USER', application=a2, user=u1)
db.session.add(rights2)

u2=Users.query.get(2)
rights3 = Rights(role='MANAGER', application=a2, user=u2)
db.session.add(rights3)

u3=Users.query.get(3)
a3=Applications.query.get(3)
rights4 = Rights(role='USER', application=a1, user=u3)
rights5 = Rights(role='USER', application=a2, user=u3)
rights6 = Rights(role='USER', application=a3, user=u3)
db.session.add(rights4)
db.session.add(rights5)
db.session.add(rights6)
db.session.commit()

nsmanage = api.namespace('manage', description='Api Management Related Operations')

rightresp = api.model('Rights_Response', {
    'email': fields.String(required=True, description='Login/Email'),
    'role': fields.String(required=True, description='[user|admin|appmanager]'),
    'code': fields.String(required=True, description='3-letter app code')
})

@nsmanage.route('/rights/<string:email>')
@nsmanage.param('email', "User's Email")
@nsmanage.response(404, 'User not found')
class GetRightsByEmail(Resource):
    @nsmanage.marshal_with(rightresp)
    def get(self, email):
        '''Fetch a user's rights given its email'''
        query = Rights.query.join(Applications, Users).options(contains_eager('user'),contains_eager('application')).filter(Users.email == email).all()
        for i in query:
            print (i.role,i.user.email,i.application.code)
        return query
        api.abort(404, message="User {} not found".format(email))

使用 swagger 或 curl 命令: curl -X GET --header 'Accept: application/json' 'http://dbbdevdb1369:5000/manage/rights/user1%40example.com'

返回:

[
  {
    "email": null,
    "role": "MANAGER",
    "code": null
  },
  {
    "email": null,
    "role": "USER",
    "code": null
  }
]

这显然不是我想要的。 查询没问题,因为“返回查询”行之前的 for 循环打印了正确的答案:

MANAGER user1@example.com APP1
USER user1@example.com APP2

我与 marshal_with 一起使用的 rightresp 模型具有正确的列(在查询中找到)

我确定这是一个新手问题(我就是),但我不知道如何使用 api 发回正确答案,即:

[
  {
    "email": "user1@example.com",
    "role": "MANAGER",
    "code": "APP1"
  },
  {
    "email": "user1@example.com",
    "role": "USER",
    "code": "APP2"
  }
]

非常感谢。 洛朗

编辑: 在数据库中生成的查询没问题(连接没问题,我想要的列被选中):

SELECT rights.id AS rights_id,
       rights.role AS rights_role,
       rights.app_id AS rights_app_id,
       rights.user_id AS rights_user_id,
       users.id AS users_id,
       users.email AS users_email,
       users.password AS users_password,
       users.created AS users_created,
       users.expires AS users_expires,
       applications.id AS applications_id,
       applications.code AS applications_code,
       applications.name AS applications_name
FROM rights JOIN applications ON applications.id = rights.app_id 
            JOIN users ON users.id = rights.user_id
WHERE users.email = :email_1

【问题讨论】:

    标签: python flask sqlalchemy flask-sqlalchemy flask-restplus


    【解决方案1】:

    您对电子邮件和代码的查询不返回字符串,而是返回 UserApplication 类的实例。我对元帅不熟悉,所以我并没有真正关注那里发生的事情。您可能希望将查询更改为:

    user = User.query.filter_by(email=email).first()
    

    您可以通过user.rights 访问其权限,并通过user.rights[index].app_id 访问其应用程序

    然后,您可能希望遍历他们的权限,并将它们添加到字典中,然后发回该字典的 jsonified 版本或类似的东西。

    【讨论】:

    • 如果我使用您的查询,在数据库中查询更改为:SELECT users_id, users_email, users_password, users_created, users_expires FROM (SELECT users.id AS users_id, users.email AS users_email, users.password AS users_password, users.created AS users_created, users.expires AS users_expires FROM users WHERE users.email = :email_1) WHERE ROWNUM
    • 我的查询得到了正确的信息:query = Rights.query.join(Applications, Users).options(contains_eager('user'),contains_eager('application')).filter(Users.email == email).all() for i in query: print (i.role,i.user.email,i.application.code) 我在这里缺少的是你所说的:循环他们的权利,并将它们添加到字典中并发回一个 jsonified 版本那个字典的版本你能提供一个例子吗?
    【解决方案2】:

    根据 Joost 的回答,我将代码修改为以下内容,并且可以正常工作:

    def get(self, email):
        '''Fetch a user's rights given its email'''
        query = Rights.query.join(Applications, Users).options(contains_eager('user'),contains_eager('application')).filter(Users.email == email).all()
        response = []
        for i in query:
            print (i.role,i.user.email,i.application.code)
            info = {
                "email": i.role,
                "role":  i.user.email,
                "code":  i.application.code,
            }
            response.append(info)
        print (response)
        return response, 200
        api.abort(404, message="User {} not found".format(email))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 2019-05-31
      • 2011-10-29
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多