Элегантная дизъюнктивная нормальная форма в Django - PullRequest
2 голосов
/ 28 мая 2010

Допустим, я определил эту модель:

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

У каждого пользователя будет несколько идентификаторов, каждый с ключом и значением. Я на 100% уверен, что хочу сохранить такой дизайн, есть внешние причины, по которым я это делаю, которые я не буду здесь проходить, поэтому я не заинтересован в том, чтобы изменить это.

Я бы хотел разработать такую ​​функцию:

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

Функция вернет всех пользователей, у которых одна из пар ключ = значение указана в ** kwargs. Вот пример использования:

get_users_by_identifiers(a=1, b=2)

Это должно вернуть всех пользователей, для которых a = 1 или b = 2. Я заметил, что способ, которым я это настроил, сводится к дизъюнктивной нормальной форме ... SQL-запрос будет выглядеть примерно так:

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

Я чувствую, что должен быть какой-то элегантный способ взять ** ввод kwargs и сделать фильтр Django на нем всего за 1-2 строки, чтобы получить этот результат. Я новичок в Django, так что я просто не знаю, как это сделать. Вот моя функция сейчас, и я абсолютно уверен, что это не лучший способ сделать это:)

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

Есть идеи? :)

Спасибо!

1 Ответ

1 голос
/ 28 мая 2010
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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...