2 Stimmen

Elegante disjunktive Normalform in Django

Nehmen wir an, ich habe dieses Modell definiert:

class Identifier(models.Model):
    user = models.ForeignKey(User)
    key = models.CharField(max_length=64)
    value = models.CharField(max_length=255)

Jeder Benutzer hat mehrere Identifikatoren, jeder mit einem Schlüssel und einem Wert. Ich bin mir zu 100 % sicher, dass ich das Design so beibehalten möchte. Es gibt externe Gründe, warum ich das tue, die ich hier nicht näher erläutern werde, daher bin ich nicht daran interessiert, dies zu ändern.

Ich würde gerne eine Funktion dieser Art entwickeln:

def get_users_by_identifiers(**kwargs):
    # something goes here
    return users

Die Funktion gibt alle Benutzer zurück, die eines der in **kwargs angegebenen Schlüssel=Wert-Paare haben. Hier ist ein Beispiel für die Verwendung:

get_users_by_identifiers(a=1, b=2)

Dies sollte alle Benutzer zurückgeben, bei denen a=1 oder b=2 ist. Mir ist aufgefallen, dass die Art und Weise, wie ich dies eingerichtet habe, auf eine disjunktive Normalform hinausläuft... die SQL-Abfrage würde etwa so aussehen:

SELECT DISTINCT(user_id) FROM app_identifier 
    WHERE (key = "a" AND value = "1") OR (key = "b" AND value = "2") ...

Ich habe das Gefühl, dass es eine elegante Möglichkeit gibt, die **kwargs-Eingabe zu nehmen und einen Django-Filter darauf zu tun, in nur 1-2 Zeilen, um dieses Ergebnis zu erzeugen. Ich bin neu in Django aber, so ich bin einfach nicht sicher, wie es zu tun. Hier ist meine Funktion jetzt, und ich bin völlig sicher, es ist nicht der beste Weg, es zu tun :)

def get_users_by_identifiers(**identifiers):
    users = []
    for key, value in identifiers.items():
        for identifier in Identifier.objects.filter(key=key, value=value):
            if not identifier.user in users:
                users.append(identifier.user)

    return users

Irgendwelche Ideen? :)

Danke!

1voto

Ignacio Vazquez-Abrams Punkte 735200
def get_users_by_identifiers(**kwargs):
    q = reduce(operator.or_, Q(identifier__key=k, identifier__value=v)
        for (k, v) in kwargs.iteritems())
    return User.objects.filter(q)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X