webentwicklung-frage-antwort-db.com.de

Sqlalchemy nach Feld in Liste filtern, aber ursprüngliche Reihenfolge beibehalten?

Ich habe ein Schuhmodell wie dieses:

class Shoe(db.Model):
id = db.Column(db.Integer, primary_key = True)
asin = db.Column(db.String(20), index = True)

Ich habe eine Liste von IDs wie ids = [2,1,3] und wenn ich nach dem Schuhmodell frage, so dass die Ergebnisse IDs in der 'IDs'-Liste haben, möchte ich zurück: [{id: 2, asin: " 111 "}, {id: 1, asin:" 113 "}, {id: 3, asin:" 42 "}], aber das Problem ist, dass bei Verwendung der folgenden Abfrageanweisung die ursprüngliche Reihenfolge nicht beibehalten wird. Die Ergebnisse werden angezeigt zurück zufällig. Wie behalte ich die Reihenfolge der Liste, nach der ich gefiltert habe?

Falsche: Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()

11
user1835351

Wenn Sie über eine vernünftige kleine Liste von IDs verfügen, können Sie einfach SQL-Abfragen für jede ID einzeln durchführen:

[Shoe.query.filter_by(id=id).one() for id in my_list_of_ids]

Für eine große Anzahl von IDs benötigen SQL-Abfragen eine lange Zeit. Dann sind Sie mit einer einzelnen Abfrage besser aufgehoben und setzen die Werte in einem zweiten Schritt in die richtige Reihenfolge (geborgt von wie man ein Objekt aus einer Liste von Objekten anhand seines Attributs in Python auswählt):

shoes = Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()
[next(s for s in shoes if s.id == id) for id in my_list_of_ids]

Dies setzt voraus, dass die IDs eindeutig sind (was in Ihrem Fall der Fall sein sollte). Die erste Methode löst eine Ausnahme aus, wenn mehrere Elemente mit derselben ID vorhanden sind.

11
Rob

Eine Möglichkeit, dieses Problem in der Vergangenheit zu lösen, ist die Verwendung eines SQL CASE-Ausdrucks , um der Datenbank mitzuteilen, in welcher Reihenfolge die Zeilen zurückgegeben werden sollen. An deinem Beispiel:

from sqlalchemy.sql.expression import case

ordering = case(
    {id: index for index, id in enumerate(my_list_of_ids)},
    value=Shoe.id
 )
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by(ordering).all()
6
bjmc

Ich habe auch das gleiche Problem bei der Verwendung einer MySQL-Datenbank. Das habe ich gemacht:

my_list = [13,14,5,6,7]
# convert my_list to str
my_list_str = ','.join(map(str, my_list))

Und so sieht meine Anfrage aus:

checkpoints = (
    db_session.query(Checkpoint)
    .filter(Checkpoint.id.in_(my_list))
    .order_by('FIELD(id, ' + my_list_str + ')')
    .all()
)

FIELD () ist eine native Funktion in MySQL.

BEARBEITEN: Ihre Abfrage sollte also so aussehen:

my_list_of_ids_str = ','.join(map(str, my_list_of_ids)) 
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by('FIELD(id, ' + my_list_of_ids_str + ')').all()

Prost

0