Elegant Disjunctive Normal Form in Django
- by Mike
Let's say I've defined this model:
class Identifier(models.Model):
user = models.ForeignKey(User)
key = models.CharField(max_length=64)
value = models.CharField(max_length=255)
Each user will have multiple identifiers, each with a key and a value. I am 100% sure I want to keep the design like this, there are external reasons why I'm doing it that I won't go through here, so I'm not interested in changing this.
I'd like to develop a function of this sort:
def get_users_by_identifiers(**kwargs):
# something goes here
return users
The function will return all users that have one of the key=value pairs specified in **kwargs. Here's an example usage:
get_users_by_identifiers(a=1, b=2)
This should return all users for whom a=1 or b=2. I've noticed that the way I've set this up, this amounts to a disjunctive normal form...the SQL query would be something like:
SELECT DISTINCT(user_id) FROM app_identifier
WHERE (key = "a" AND value = "1") OR (key = "b" AND value = "2") ...
I feel like there's got to be some elegant way to take the **kwargs input and do a Django filter on it, in just 1-2 lines, to produce this result. I'm new to Django though, so I'm just not sure how to do it. Here's my function now, and I'm completely sure it's not the best way to do it :)
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
Any ideas? :)
Thanks!