2017-12-29 33 views
0

flask-sqlalchemy 및 Postgres DB로 Flask 기반 API 응용 프로그램을 구축하고 있습니다.SQLAlchemy 개체 컬렉션에 외부 데이터 추가

  • users DB의 테이블에는 각 사용자에 대한 레코드가 있습니다. 이 테이블의 PK는 username입니다 (여기서는 특별한 것이 없습니다).
  • performance DB의 테이블에는 사용자 성능이 있습니다. 이 테이블의 PK는 날짜입니다. 이 테이블의 각 사용자에 대해 username이라는 열이 있습니다. (일부 사람들은이 구조가 이상적이지 않다는 것을 알고 있습니다. 그러나 관련이없는 요구 사항에 의해 요구됩니다.)

예 :

PK = "username", tablename = "users" 

| username | firstname | lastname | 
----------------------------------- 
| alice | Alice  | Johns | 
| bob  | Bob  | Speed | 


PK = "timestamp", tablename = "performance" 

| timestamp | alice | bob | 
----------------------------------- 
| 2017-11-2 | 1  | 5 | 
| 2017-11-3 | 6  | 9 | 

내가 users 테이블에 액세스 SQLAlchemy의를 사용합니다.

Date 매개 변수를 받고 해당 날짜에 성능이있는 모든 사용자의 컬렉션을 반환하는 REST API를 만들려고합니다.

올바른 SQLAlchemy 쿼리는 무엇이므로 각 사용자에 대해 성능 값을 독립적으로 선택하지 않습니다.

+0

기다립니다, 각 사용자에 대한 열이있는 테이블이? 아니면'(date, user_id, value)'와 같은 것을 가지고 있다는 뜻입니까? –

+0

각 사용자에 대한 열이있는 시계열 테이블 (사용자 수가 정적이며 변경되지 않음) – Miro

+0

질문을 처음부터 다시 작성합니다. 다시 열어 볼 수 있습니까? tnx – Miro

답변

0

스키마를 변경할 수없는 경우 성능 데이터를 unpivot하고 사용자와 가입 할 수 있습니다. 아무 것도 제공하지 된 이후 관계에 대한 샘플 매핑 :

In [2]: class User(Base): 
    ...:  __tablename__ = "users" 
    ...:  username = Column(Unicode(255), primary_key=True) 
    ...:  firstname = Column(Unicode(255)) 
    ...:  lastname = Column(Unicode(255)) 
    ...:  

In [3]: class Performance(Base): 
    ...:  __tablename__ = "performance" 
    ...:  timestamp = Column(Date, primary_key=True) 
    ...:  # NOTE: this works **only** in a class body context, 
    ...:  # and your schema shouldn't be like this anyway. 
    ...:  for name in ['alice', 'bob']: 
    ...:   locals()[name] = Column(Integer, nullable=False) 
    ...:   

검사를 사용하여 성능 데이터가 사용자 이름을 가져옵니다. 성능 값이

In [15]: from sqlalchemy.dialects import postgresql 
    ...: performance = session.query(
    ...:   func.unnest(postgresql.array(users)).label('username'), 
    ...:   func.unnest(postgresql.array(
    ...:    [getattr(Performance, name) 
    ...:    for name in users])).label('value')).\ 
    ...:  filter(Performance.timestamp == '2017-11-2').\ 
    ...:  subquery() 
    ...: 

가입 사용자 :

In [24]: session.query(User, performance.c.value).\ 
    ...:  join(performance, performance.c.username == User.username).\ 
    ...:  all() 
Out[24]: 
[(<__main__.User at 0x7f79eb5d2c88>, 1), 
(<__main__.User at 0x7f79eb5d2cf8>, 5)] 
- 그것을 할 수있는 하나의 방법

In [11]: users = inspect(Performance).attrs.keys()[1:] 

In [12]: users 
Out[12]: ['alice', 'bob'] 

형성 unpivot query : 당신은 또한 사용자 이름의 정적 목록에 잡을 수


성능 데이터가 (timestamp, username, value) 튜플로 저장되도록 스키마를 변경 했습니까? 간단하게이 작업을 수행 울드 :

In [2]: class User(Base): 
    ...:  __tablename__ = "users" 
    ...:  ... 
    ...:  performance = relationship("BetterPerformance") 
    ...: 

In [25]: class BetterPerformance(Base): 
    ...:  __tablename__ = "better_performance" 
    ...:  timestamp = Column(Date, primary_key=True) 
    ...:  username = Column(ForeignKey('users.username'), primary_key=True) 
    ...:  value = Column(Integer, nullable=False) 
    ...: 

In [13]: session.query(User, BetterPerformance.value).\ 
    ...:  join(User.performance).\ 
    ...:  filter(BetterPerformance.timestamp == '2017-11-2').\ 
    ...:  all() 
Out[13]: 
[(<__main__.User at 0x7f6ae3282c18>, 1), 
(<__main__.User at 0x7f6ae3282ba8>, 5)] 

또는 :

In [17]: session.query(User).\ 
    ...:  join(User.performance).\ 
    ...:  options(contains_eager(User.performance)).\ 
    ...:  filter(BetterPerformance.timestamp == '2017-11-2').\ 
    ...:  all() 
Out[17]: [<__main__.User at 0x7f6ae3282c18>, <__main__.User at 0x7f6ae3282ba8>] 

In [18]: [u.performance[0].value for u in _] 
Out[18]: [1, 5]