sqlalchemy 모델의 정의 된 열을 반복하는 방법?
SQLAlchemy 모델에 정의 된 열 목록을 반복하는 방법을 알아 내려고했습니다. 몇 가지 모델에 직렬화 및 복사 메서드를 작성하기 위해 그것을 원합니다. obj.__dict__
SA 특정 항목이 많이 포함되어 있으므로 반복 할 수 없습니다 .
누구든지 다음에서 id
및 desc
이름을 얻는 방법을 알고 있습니까?
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.c 및 Mapper.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)
To get an as_dict
method on all of my classes I used a Mixin
class which uses the technics described by Ants Aasma.
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
And then use it like this in your classes
class MyClass(BaseMixin, Base):
pass
That way you can invoke the following on an instance of MyClass
.
> myclass = MyClass()
> myclass.as_dict()
Hope this helps.
I've played arround with this a bit further, I actually needed to render my instances as dict
as the form of a HAL object with it's links to related objects. So I've added this little magic down here, which will crawl over all properties of the class same as the above, with the difference that I will crawl deeper into Relaionship
properties and generate links
for these automatically.
Please note that this will only work for relationships have a single primary key
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
Assuming you're using SQLAlchemy's declarative mapping, you can use __mapper__
attribute to get at the class mapper. To get all mapped attributes (including relationships):
obj.__mapper__.attrs.keys()
If you want strictly column names, use obj.__mapper__.column_attrs.keys()
. See the documentation for other views.
https://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.Mapper.attrs
self.__dict__
returns a dict where keys are attribute names and values the values of the object.
/!\ there is a supplementary attribute: '_sa_instance_state' but you can handle it :)
I know this is an old question, but what about:
class JobStatus(Base):
...
def columns(self):
return [col for col in dir(self) if isinstance(col, db.Column)]
Then, to get column names: jobStatus.columns()
That would return ['id', 'desc']
Then you can loop through, and do stuff with the columns and values:
for col in jobStatus.colums():
doStuff(getattr(jobStatus, col))
'programing' 카테고리의 다른 글
Ruby는 Tail Call 최적화를 수행합니까? (0) | 2020.09.05 |
---|---|
여러 조건이있는 javascript if 문이 모든 조건을 테스트합니까? (0) | 2020.09.05 |
tomcat-CATALINA_BASE 및 CATALINA_HOME 변수 (0) | 2020.09.05 |
Java 애플리케이션을 다시 시작하려면 어떻게해야합니까? (0) | 2020.09.05 |
전략 패턴과 종속성 주입의 차이점은 무엇입니까? (0) | 2020.09.05 |