简体   繁体   中英

How to get key-value pair in one object while joining two tables in SQLAlchemy in Python?

I have two tables Employee and Department, After joining I am getting a result like this

[
    {
      "name": "Omar Hasan",
      "id": 1,
      "email": "omar@example.com"
    },
    {
      "dept_name": "Engineering",
      "id": 2
    }
]

But I want the result in one object like

[
    {
      "name": "Omar Hasan",
      "id": 1,
      "email": "omar@example.com",
      "dept_name": "Engineering",
    },
    ......
    ......
]

Here is my code

Models, dept_id is FK in Employee table

class Employee(Base):
    __tablename__ = "employees"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    email = Column(String, unique=True, index=True)
    password = Column(String)
    is_active = Column(Boolean, default=True)
    salary = Column(Numeric(10, 2))
    dept_id = Column(Integer, ForeignKey('departments.id'), nullable=False)

    department = relationship("Department", back_populates="owner")

class Department(Base):
    __tablename__ = "departments"

    id = Column(Integer, primary_key=True, index=True)
    dept_name = Column(String, unique=True, index=True)

    owner = relationship("Employee", back_populates="department")

Here is the query which produces the above result

return db.query(models.Employee, models.Department)\
        .join(models.Employee.department)\
        .options(
        Load(models.Employee).load_only("name", "email"),
        Load(models.Department).load_only("dept_name")
        )\
        .all()

Instead of explicitly joining the two models you can use the relationships defined between them to allow access to the department name when building the results.

# Query Employee only
res = session.query(Employee)\
        .options(
        orm.Load(Employee).load_only("name", "email"),
        orm.Load(Department).load_only("dept_name")
        )\
        .all()
 
mappings = []
for employee in res:
    d = {
        'name': employee.name,
        'id': employee.id,
        'email': employee.email,
        'dept_name' employee.department.name
    }
    mappings.append(d)

We can make building the result dictionaries more elegant by defining a department name property on Employee :

class Employee(Base):
    ...
    
    @property
    def dept_name(self):
        return self.department.dept_name

...

# List the attributes that we want
attrs = ['name', 'id', 'email', 'dept_name']
# Build the mappings using dictionary comprehensions
mappings = [{attr: getattr(e, attr) for attr in attrs} for e in res]

Rather than a standard property , we could use a hybrid_property instead, but there isn't much value in doing this here unless you want to use it in queries.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM