Diferença entre filter e filter_by em SQLAlchemy

304

Alguém poderia explicar a diferença entre filtere filter_byfunções no SQLAlchemy? Qual devo usar?

bodacydo
fonte

Respostas:

393

filter_by é usado para consultas simples nos nomes das colunas usando kwargs regulares, como

db.users.filter_by(name='Joe')

O mesmo pode ser feito com o filternão uso de kwargs, mas com o operador de igualdade '==', que foi sobrecarregado no objeto db.users.name:

db.users.filter(db.users.name=='Joe')

Você também pode escrever consultas mais poderosas usando filter, como expressões como:

db.users.filter(or_(db.users.name=='Ryan', db.users.country=='England'))

Daniel Velkov
fonte
22
Como isso funciona sob o capô? Não db.users.name=='Ryan'avaliaria uma vez uma constante e depois não teria sentido a partir de então? Parece que seria necessário usar um lambda para que isso funcionasse.
Hamish Grubijan
46
o operador de igualdade está sobrecarregado
Daniel Velkov 27/02
9
type(model.column_name == 'asdf')sqlalchemy.sql.elements.BinaryExpression
Nick T
11
Tenha cuidado ao usar .filter. uma consulta como id=12345, query(users).filter(id == id)não será filtrada users.id. Em vez disso, ele avaliará id == idcomo Truee retornará todos os usuários. Você precisa usar .filter(users.id == id)(como demonstrado acima). Eu cometi esse erro hoje cedo.
Nico Cernek
118

Na verdade, nós os fundimos originalmente, ou seja, havia um método semelhante ao "filtro" que aceitava *argse **kwargs, onde você podia passar uma expressão SQL ou argumentos de palavras-chave (ou ambos). Na verdade, acho isso muito mais conveniente, mas as pessoas sempre ficaram confusas com isso, pois geralmente ainda estão superando a diferença entre column == expressione keyword = expression. Então nós os separamos.

zzzeek
fonte
30
Eu acho que o seu ponto sobre column == expressionvs. keyword = expressioné o ponto chave a ser feito sobre a diferença entre filtere filter_by. Obrigado!
Hollister
2
Eu sou novo no sqlalchemy, então desculpe-me se esta for uma pergunta estúpida, mas filter_by () não parece permitir nem mesmo as condições muito simples, como "preço> = 100". Então, por que a função filter_by () de qualquer maneira, se você pode usá-la apenas para as condições mais simples, como "preço = 100"?
PawelRoman #
18
porque as pessoas gostam
zzzeek
3
Existe alguma diferença de desempenho entre eles? Eu estava pensando que filter_bypoderia ser um pouco mais rápido que filter.
Devi
6
O objetivo do uso filter_byé ser capaz de escrever apenas o nome do campo, para essa classe, sem perguntas - embora flterexija o objeto da coluna real - que normalmente exige que você digite (e leia) pelo menos um nome de classe redundante. Portanto, se alguém deseja filtrar por igualdade, é bastante conveniente.
jsbueno
36

filter_byusa argumentos de palavra-chave, enquanto que filterpermite argumentos de filtragem python comofilter(User.name=="john")

Johannes Charra
fonte
34

É um açúcar de sintaxe para uma gravação mais rápida de consultas. Sua implementação em pseudocódigo:

def filter_by(self, **kwargs):
    return self.filter(sql.and_(**kwargs))

Para AND, você pode simplesmente escrever:

session.query(db.users).filter_by(name='Joe', surname='Dodson')

btw

session.query(db.users).filter(or_(db.users.name=='Ryan', db.users.country=='England'))

pode ser escrito como

session.query(db.users).filter((db.users.name=='Ryan') | (db.users.country=='England'))

Além disso, você pode obter objetos diretamente por PK através do getmétodo:

Users.query.get(123)
# And even by a composite PK
Users.query.get(123, 321)

Ao usar o getcaso, é importante que o objeto possa ser retornado sem a solicitação do banco de dados a partir da identity mapqual pode ser usado como cache (associado à transação)

enomad
fonte
Estes exemplos de código são enganosos: Classes e instâncias de tabela base declarativas não têm métodos de filtro nem de consulta; eles usam a sessão.
Tartarugas São Bonitas
Eu reproduzo users.filterda resposta anterior. E pode ser que seja minha culpa :) O queryatributo é query_property e é um açúcar bastante comum hoje em dia
enomad 16/16