метод итерации по определенным столбцам модели 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
(для больших объектов).
Спасибо за помощь.
7 ответов:
вы можете использовать следующие функции:
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
, у вас есть , так что вы можете сделать:for c in JobStatus.__table__.columns: print c for c in JobStatus.__table__.foreign_keys: print c
посмотреть как открыть свойства таблицы из SQLAlchemy сопоставленный объект - аналогичный вопрос.
Edit by Mike: пожалуйста, смотрите такие функции, как маппер.c и маппер.mapped_table. Если через 0,8 и выше, также посмотреть маппер.attrs и связанные с этим функции.
пример маппер.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
, Так что вместо исходного имени Поля id, вы получите 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)
для получения
as_dict
метод на всех моих классах я использовалMixin
класс, который использует технику, описанную Муравьи 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
а затем использовать его, как это в ваших классах
class MyClass(BaseMixin, Base): pass
таким образом, вы можете ссылаться на экземпляр
MyClass
.> myclass = MyClass() > myclass.as_dict()
надеюсь, что это помогает.
я играл с этим немного дальше, мне действительно нужно было сделать мои экземпляры как
dict
как форма а HAL object С его ссылками на связанные объекты. Поэтому я добавил сюда эту маленькую магию, которая будет ползать по всем свойствам класса так же, как и выше, с той разницей, что я буду ползти глубже в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
предполагая, что вы используете декларативное отображение SQLAlchemy, вы можете использовать
__mapper__
атрибут, чтобы получить на класс 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
Я знаю, что это старый вопрос, но как насчет:
class JobStatus(Base): ... def columns(self): return [col for col in dir(self) if isinstance(col, db.Column)]
затем, чтобы получить имена столбцов:
jobStatus.columns()
что бы вернуть
['id', 'desc']
затем вы можете перебирать и делать вещи со столбцами и значениями:
for col in jobStatus.colums(): doStuff(getattr(jobStatus, col))