Existe uma maneira simples de iterar sobre o nome da coluna e os pares de valores?
Minha versão do sqlalchemy é 0.5.6
Aqui está o código de exemplo em que tentei usar o dict (linha), mas ele lança a exceção TypeError: o objeto 'User' não é iterável
import sqlalchemy
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
print "sqlalchemy version:",sqlalchemy.__version__
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
users_table = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
)
metadata.create_all(engine)
class User(declarative_base()):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, name):
self.name = name
Session = sessionmaker(bind=engine)
session = Session()
user1 = User("anurag")
session.add(user1)
session.commit()
# uncommenting next line throws exception 'TypeError: 'User' object is not iterable'
#print dict(user1)
# this one also throws 'TypeError: 'User' object is not iterable'
for u in session.query(User).all():
print dict(u)
A execução deste código nas saídas do meu sistema:
sqlalchemy version: 0.5.6
Traceback (most recent call last):
File "untitled-1.py", line 37, in <module>
print dict(u)
TypeError: 'User' object is not iterable
python
sqlalchemy
Anurag Uniyal
fonte
fonte
sqlalchemy.util.KeyedTuple
qual é o objeto de linha do título da pergunta. No entanto, a consulta na pergunta usa a classe model (mapeada), portanto, o tipo de objeto de linha é a classe model em vez desqlalchemy.util.KeyedTuple
.Respostas:
Você pode acessar o interno
__dict__
de um objeto SQLAlchemy, como o seguinte:fonte
dictret = dict(row.__dict__); dictret.pop('_sa_instance_state', None)
__dict__
inclui uma_sa_instance_state
entrada que deve ser removida. se você atualizar para uma versão futura e outros atributos forem adicionados, poderá ser necessário voltar e lidar manualmente com eles. se você deseja apenas dados da coluna (por exemplo, pegar uma lista de instâncias de uma consulta e soltá-las em um quadro de dados do pandas), então,{col.name: getattr(self, col.name) for col in self.__table__.columns}
conforme respondido por Anurag Uniyal (com correções importantes dos comentários a essa resposta), parece mais sucinto e com erros prova.dict(u)
e afirma corretamente que lança aTypeError
.Como não consegui uma boa resposta, uso o seguinte:
Edit: se a função acima é muito longa e não é adequada para alguns gostos, aqui está um liner (python 2.7+)
fonte
return dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
.row2dict = lambda row: dict((col, getattr(row, col)) for col in row.__table__.columns.keys())
para torná-lo um forro de um real, mas eu prefiro o meu código para ser legível, horizontalmente short, verticalmente longax = Column('y', Integer, primary_key=True)
? Nenhuma dessas soluções funciona nesse caso.return {c.name: getattr(self, c.name) for c in self.__table__.columns}
Conforme @zzzeek nos comentários:
fonte
query(MyModel).all()
: O objeto MyModel não é iterável.No SQLAlchemy v0.8 e mais recente, use o sistema de inspeção .
Observe que esse
.key
é o nome do atributo, que pode ser diferente do nome da coluna, por exemplo, no seguinte caso:Este método também funciona para
column_property
.fonte
sqlalchemy.inspect(obj).unloaded
linhas têm uma
_asdict()
função que fornece um ditadofonte
como @balki mencionado:
O
_asdict()
método pode ser usado se você estiver consultando um campo específico porque ele é retornado como um KeyedTuple .Considerando que, se você não especificar uma coluna, poderá usar um dos outros métodos propostos - como o fornecido por @charlax. Observe que esse método é válido apenas para 2.7+.
fonte
.first()
método)?Pergunta antiga, mas como esse é o primeiro resultado para "ditar sqlalchemy row" no Google, ele merece uma resposta melhor.
O objeto RowProxy que SqlAlchemy retorna possui o método items (): http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.RowProxy.items
Ele simplesmente retorna uma lista de tuplas (chave, valor). Portanto, é possível converter uma linha em ditado usando o seguinte:
No Python <= 2.6:
Em Python> = 2.7:
fonte
list_of_dicts = [dict(row.items()) for row in rows]
table_name_column_name
, se você quiser nomes diferentes (por exemplo, apenascolumn_name
), use o.label
métodosession.query( MyTable.column_name.label('column_name'), ... )
Assumindo que as seguintes funções serão adicionadas,
class User
o seguinte retornará todos os pares de valores-chave de todas as colunas:ao contrário das outras respostas, todos, exceto apenas os atributos do objeto, são retornados, que são
Column
atributos no nível de classe do objeto. Portanto, nenhum_sa_instance_state
ou qualquer outro atributo SQLalchemy ou você adiciona ao objeto estão incluídos. ReferênciaEdição: esqueça de dizer que isso também funciona em colunas herdadas.
hybrid_propery
extensãoSe você também deseja incluir
hybrid_property
atributos, o seguinte funcionará:Suponho aqui que você marque as colunas com um começo
_
para indicar que deseja ocultá-las, porque você acessa o atributo por umhybrid_property
ou simplesmente não deseja mostrá-las. ReferênciaTipp
all_orm_descriptors
também retorna hybrid_method e AssociationProxy, se você também quiser incluí-los.Comentários a outras respostas
Toda resposta (como 1 , 2 ) que, com base no
__dict__
atributo, simplesmente retorna todos os atributos do objeto. Isso pode ser muito mais atributos do que você deseja. Como eu triste isso inclui_sa_instance_state
ou qualquer outro atributo que você definir sobre esse objeto.Todas as respostas (como 1 , 2 ) baseadas na
dict()
função funcionam apenas nos objetos de linha SQLalchemy retornados,session.execute()
não nas classes com as quais você define trabalhar, como asclass User
da pergunta.A resposta de solução que se baseia
row.__table__.columns
definitivamente não funcionará.row.__table__.columns
contém os nomes das colunas do banco de dados SQL. Eles podem ser iguais apenas ao nome dos atributos do objeto python. Se não, você recebe umAttributeError
. Para respostas (como 1 , 2 ), com baseclass_mapper(obj.__class__).mapped_table.c
nela, é a mesma.fonte
fonte
Após a resposta @balki, desde SQLAlchemy 0.8, você pode usar _asdict (), disponível para objetos KeyedTuple. Isso torna uma resposta bastante direta à pergunta original. Apenas mude no seu exemplo as duas últimas linhas (o loop for) desta:
Isso funciona porque no código acima u é um objeto da classe tipo KeyedTuple , pois .all () retorna uma lista de KeyedTuple. Portanto, ele tem o método _asdict () , que retorna u como um dicionário.
Escreva a resposta por @STB: AFAIK, ao lado de .all () retorna uma lista de KeypedTuple. Portanto, o acima funcionará se você especificar uma coluna ou não, desde que esteja lidando com o resultado de .all () aplicado a um objeto de Consulta.
fonte
.all()
retorna uma lista deUser
instâncias, portanto, isso não funciona.User
instâncias não têm um_asdict
método. Veja gist.github.com/RazerM/2eff51571b3c70e8aeecd303c2a2bc8dA expressão pela qual você está iterando é avaliada na lista de objetos de modelo , não em linhas. Portanto, o seguinte é o uso correto deles:
Você realmente precisa convertê-los em ditados? Claro, existem várias maneiras, mas você não precisa da parte ORM do SQLAlchemy:
Atualização : Dê uma olhada no
sqlalchemy.orm.attributes
módulo. Ele possui um conjunto de funções para trabalhar com o estado do objeto, que podem ser úteis para você, especialmenteinstance_dict()
.fonte
Consulte a resposta de Alex Brasetvik , você pode usar uma linha de código para resolver o problema
Sob a seção de comentários da resposta de Alex Brasetvik, zzzeek, o criador do SQLAlchemy, afirmou que este é o "método correto" para o problema.
fonte
resultproxy
?Você pode tentar fazer dessa maneira.
Ele usa um método interno no objeto de consulta que retorna um objeto dictonário do objeto de consulta.
referências: https://docs.sqlalchemy.org/en/latest/orm/query.html
fonte
_asdict()
método interno que fecha os nomes dos campos com valores de campo e retorna o resultado como um dicionário.u
no meu caso é uma string, e eu recebo erro `` Model 'objeto não tem nenhum atributo' _asdict'` @hllau abaixo funcionou para mimEncontrei este post porque estava procurando uma maneira de converter uma linha SQLAlchemy em um ditado. Estou usando o SqlSoup ... mas a resposta foi criada por mim, então, se isso puder ajudar alguém, aqui estão meus dois centavos:
fonte
RowProxy
(c
nesta resposta) adere ao protocolo de mapeamento, para que você possa simplesmente ligardict(c)
.Você pode converter o objeto sqlalchemy em dicionário como este e retorná-lo como json / dictionary.
Funções auxiliares:
Função do driver:
fonte
Dois caminhos:
1
2)
fonte
Os documentos oferecem uma solução muito simples:
ResultRow._asdict()
fonte
Aqui está como o Elixir faz isso. O valor dessa solução é que ela permite incluir recursivamente a representação das relações no dicionário.
fonte
Com este código, você também pode adicionar à sua consulta "filtro" ou "associação" e este trabalho!
fonte
Isso deve funcionar.
fonte
Eu tenho uma variação na resposta de Marco Mariani, expressa como decoradora. A principal diferença é que ele manipulará listas de entidades, além de ignorar com segurança outros tipos de valores de retorno (o que é muito útil ao escrever testes usando zombarias):
fonte
Para completar a resposta de @Anurag Uniyal, aqui está um método que seguirá recursivamente os relacionamentos:
fonte
d[relationship.key] = to_dict(val,with_relationships) if val else None
Sou um programador Python recém-formado e tive problemas para acessar o JSON com tabelas Associadas. Usando informações das respostas aqui, criei uma função para retornar resultados razoáveis ao JSON, onde os nomes das tabelas estão incluídos, evitando a necessidade de um alias ou a colisão de campos.
Basta passar o resultado de uma consulta de sessão:
test = Session (). query (VMInfo, Customer) .join (Customer) .order_by (VMInfo.vm_name) .limit (50) .offset (10)
json = sqlAl2json (teste)
fonte
se a coluna da tabela de modelos não for igual à coluna mysql.
tal como :
Precisa usar:
se você usar dessa maneira, poderá obter modify_time e create_time, ambos são None
Porque o nome dos atributos da classe não é igual ao armazenamento da coluna no mysql
fonte
Retorne o conteúdo deste: class:
.KeyedTuple
as a dictionaryfonte
Para o bem de todos e de mim, aqui está como eu o uso:
fonte
Esta função pode ajudar. Não consigo encontrar uma solução melhor para resolver o problema quando o nome do atributo é diferente dos nomes das colunas.
fonte
Você precisará dele em qualquer lugar do seu projeto, eu apriciate @anurag respondeu que funciona bem. até o momento, eu estava usando, mas ele bagunçará todo o seu código e também não funcionará com a alteração de entidade.
Em vez disso, tente herdar sua classe de consulta base em SQLAlchemy
depois disso, onde quer que você defina seu método "as_dict", o objeto estará lá.
fonte
Com o python 3.8+, podemos fazer isso com a classe de dados e o
asdict
método que acompanha:A chave é usar o
@dataclass
decorador e anotar cada coluna com seu tipo (a: str
parte doname: str = Column(String)
linha).Observe também que, como o
email
não é anotado, ele não é incluído noquery_result_dict
.fonte
Na maioria dos cenários, o nome da coluna é adequado para eles. Mas talvez você escreva o código da seguinte maneira:
o column.name "user_email" enquanto o nome do campo for "email", o column.name não funcionou bem como antes.
sqlalchemy_base_model.py
Também escrevo a resposta aqui
fonte