Я пытался выяснить, как перебирать список столбцов, определенных в модели 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
(для более крупных объектов).
источник
__table__.columns
это даст вам имена полей SQL, а не имена атрибутов, которые вы использовали в определениях ORM (если они отличаются).'_sa_' != k[:4]
наnot k.startswith('_sa_')
?inspect(JobStatus).columns.keys()
model.__dict__[column]
sqlalchemy, не обнаруживает изменений.Вы можете получить список определенных свойств в картографе. В вашем случае вас интересуют только объекты 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)]
источник
class_mapper
необходимо импортировать изsqlalchemy.orm
inspect()
, который возвращает тот же объект сопоставления, что иclass_mapper()
. docs.sqlalchemy.org/en/latest/core/inspection.htmlЯ понимаю, что это старый вопрос, но я только что столкнулся с тем же требованием и хотел бы предложить альтернативное решение для будущих читателей.
Как отмечает Джош, полные имена полей 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__.column_attrs.keys()
. См. Документацию для других представлений.https://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.Mapper.attrs
источник
Чтобы получить
as_dict
метод для всех моих классов, я использовал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
.Надеюсь это поможет.
Я немного поиграл с этим, мне действительно нужно было визуализировать мои экземпляры как
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
источник
from sqlalchemy.orm import class_mapper, ColumnProperty
поверх фрагмента кодавозвращает dict, где ключи - это имена атрибутов, а значения - значения объекта.
/! \ есть дополнительный атрибут: '_sa_instance_state', но вы справитесь :)
источник
Я хочу динамически получать данные о конкретном экземпляре модели. Я использовал этот код.
def to_json(instance): # get columns data data = {} columns = list(instance.__table__.columns) for column in columns: data[column.name] = instance.__dict__[column.name] return data
источник
Я знаю, что это старый вопрос, но как насчет:
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))
источник