[python] sqlalchemy 모델의 정의 된 열을 반복하는 방법?

SQLAlchemy 모델에 정의 된 열 목록을 반복하는 방법을 알아 내려고했습니다. 몇 가지 모델에 직렬화 및 복사 메서드를 작성하기 위해 그것을 원합니다. obj.__dict__SA 특정 항목이 많이 포함되어 있으므로 반복 할 수 없습니다 .

누구든지 다음에서 iddesc이름을 얻는 방법을 알고 있습니까?

class JobStatus(Base):
    __tablename__ = 'jobstatus'

    id = Column(Integer, primary_key=True)
    desc = Column(Unicode(20))

이 작은 경우에는 다음을 쉽게 만들 수 있습니다.

def logme(self):
    return {'id': self.id, 'desc': self.desc}

하지만 dict(더 큰 개체의 경우) 자동 생성되는 것을 선호합니다 .



답변

다음 기능을 사용할 수 있습니다.

def __unicode__(self):
    return "[%s(%s)]" % (self.__class__.__name__, ', '.join('%s=%s' % (k, self.__dict__[k]) for k in sorted(self.__dict__) if '_sa_' != k[:4]))

SA 매직 속성 은 제외 되지만 관계는 제외되지 않습니다. 따라서 기본적으로 종속성, 부모, 자식 등을로드 할 수 있습니다. 이는 확실히 바람직하지 않습니다.

그러나에서 상속 Base하면 __table__속성이 있으므로 다음을 수행 할 수 있기 때문에 실제로 훨씬 쉽습니다 .

for c in JobStatus.__table__.columns:
    print c

for c in JobStatus.__table__.foreign_keys:
    print c

참조 SQLAlchemy의 매핑 개체에서 테이블 속성을 발견하는 방법 비슷한 질문을 -.

Mike 편집 : Mapper.cMapper.mapped_table 과 같은 함수를 참조하십시오 . 0.8 이상을 사용하는 경우 Mapper.attrs 및 관련 함수 도 참조하십시오 .

Mapper.attrs의 예 :

from sqlalchemy import inspect
mapper = inspect(JobStatus)
for column in mapper.attrs:
    print column.key


답변

매퍼에서 정의 된 속성 목록을 가져올 수 있습니다. 귀하의 경우에는 ColumnProperty 객체에만 관심이 있습니다.

from sqlalchemy.orm import class_mapper
import sqlalchemy

def attribute_names(cls):
    return [prop.key for prop in class_mapper(cls).iterate_properties
        if isinstance(prop, sqlalchemy.orm.ColumnProperty)]


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 동일한 요구 사항을 발견했으며 미래의 독자에게 대안 솔루션을 제공하고 싶습니다.

조쉬 노트로, 전체 SQL 필드 이름에 의해 반환됩니다 JobStatus.__table__.columns, 그래서보다는 원래 필드 이름 아이디 , 당신은 얻을 것이다 jobstatus.id . 가능한 한 유용하지 않습니다.

원래 정의 된대로 필드 이름 목록을 얻는 솔루션 _data은 전체 데이터를 포함하는 열 개체 에서 속성 을 보는 것 입니다. 를 보면 JobStatus.__table__.columns._data다음과 같습니다.

{'desc': Column('desc', Unicode(length=20), table=<jobstatus>),
 'id': Column('id', Integer(), table=<jobstatus>, primary_key=True, nullable=False)}

여기에서 간단 JobStatus.__table__.columns._data.keys()하고 깔끔한 목록을 제공하는 호출 할 수 있습니다 .

['id', 'desc']


답변

self.__table__.columns특정 클래스에 정의 된 열만 제공합니다. 즉, 상속 된 열이 없습니다. 모두 필요한 경우 self.__mapper__.columns. 귀하의 예에서 나는 아마도 다음과 같은 것을 사용할 것입니다.

class JobStatus(Base):

    ...

    def __iter__(self):
        values = vars(self)
        for attr in self.__mapper__.columns.keys():
            if attr in values:
                yield attr, values[attr]

    def logme(self):
        return dict(self)


답변

SQLAlchemy의 선언적 매핑을 사용한다고 가정하면 __mapper__특성을 사용 하여 클래스 매퍼를 가져올 수 있습니다 . 모든 매핑 된 속성 (관계 포함)을 가져 오려면 :

obj.__mapper__.attrs.keys()

엄격하게 열 이름을 원하면 obj.__mapper__.column_attrs.keys(). 다른보기에 대해서는 문서를 참조하십시오.

https://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.Mapper.attrs


답변

as_dict모든 클래스에 대한 메소드 를 얻기 위해 Ants Aasma가Mixin 설명하는 기술을 사용하는 클래스를 사용했습니다 .

class BaseMixin(object):                                                                                                                                                                             
    def as_dict(self):                                                                                                                                                                               
        result = {}                                                                                                                                                                                  
        for prop in class_mapper(self.__class__).iterate_properties:                                                                                                                                 
            if isinstance(prop, ColumnProperty):                                                                                                                                                     
                result[prop.key] = getattr(self, prop.key)                                                                                                                                           
        return result

그런 다음 수업에서 이렇게 사용하십시오.

class MyClass(BaseMixin, Base):
    pass

이렇게하면의 인스턴스에서 다음을 호출 할 수 있습니다 MyClass.

> myclass = MyClass()
> myclass.as_dict()

도움이 되었기를 바랍니다.


나는 이것으로 조금 더 놀아 보았고 실제로 관련 객체에 대한 링크가 dict있는 HAL 객체 의 형태로 인스턴스를 렌더링 해야했습니다. 그래서 저는 여기에이 작은 마법을 추가했습니다. 위와 같은 클래스의 모든 속성을 탐색 할 것입니다. 차이점은 Relaionship속성을 더 깊이 탐색 하고 links자동으로 생성 할 것입니다.

이것은 단일 기본 키가있는 관계에서만 작동합니다.

from sqlalchemy.orm import class_mapper, ColumnProperty
from functools import reduce


def deepgetattr(obj, attr):
    """Recurses through an attribute chain to get the ultimate value."""
    return reduce(getattr, attr.split('.'), obj)


class BaseMixin(object):
    def as_dict(self):
        IgnoreInstrumented = (
            InstrumentedList, InstrumentedDict, InstrumentedSet
        )
        result = {}
        for prop in class_mapper(self.__class__).iterate_properties:
            if isinstance(getattr(self, prop.key), IgnoreInstrumented):
                # All reverse relations are assigned to each related instances
                # we don't need to link these, so we skip
                continue
            if isinstance(prop, ColumnProperty):
                # Add simple property to the dictionary with its value
                result[prop.key] = getattr(self, prop.key)
            if isinstance(prop, RelationshipProperty):
                # Construct links relaions
                if 'links' not in result:
                    result['links'] = {}

                # Get value using nested class keys
                value = (
                    deepgetattr(
                        self, prop.key + "." + prop.mapper.primary_key[0].key
                    )
                )
                result['links'][prop.key] = {}
                result['links'][prop.key]['href'] = (
                    "/{}/{}".format(prop.key, value)
                )
        return result


답변

self.__dict__

키는 속성 이름이고 값은 객체의 값인 dict를 반환합니다.

/! \ 보조 속성 ‘_sa_instance_state’가 있지만 처리 할 수 ​​있습니다. 🙂