Nate Pinchot
Nate Pinchot

Reputation: 3318

Best practices method of implementing a django OR query from an iterable?

I am implementing a one off data importer where I need to search for existing slugs. The slugs are in an array. What is the accepted best practices way of converting an array to an OR query?

I came up with the following, which works, but feels like way too much code to accomplish something this simple.

# slug might be an array or just a string
# ex:
slug = [ "snakes", "snake-s" ] # in the real world this is generated from directory structure on disk

# build the query
query = MyModel.objects
if hasattr(slug, "__iter__"):
    q = Q()
    for s in slug:
        q = q.__or__(Q(slug=s))
    query = query.filter(q)
else:
    query = query.filter(slug=slug)

Upvotes: 3

Views: 193

Answers (4)

Francis Yaconiello
Francis Yaconiello

Reputation: 10919

slug = ["snakes", "snake-s" ] # in the real world this is generated from directory structure on disk

# build the query
query = MyModel.objects
if hasattr(slug, "__iter__"):
    q_list = []
    for s in slug:
        q_list.append(Q(slug=s))
    query = query.filter(reduce(operator.or_, q_list))
else:
    query = query.filter(slug=slug)
  • q_list = [] create a list of Q clauses
  • reduce(operator.or_, q_list) implode the list with or operators

read this: http://www.michelepasin.org/techblog/2010/07/20/the-power-of-djangos-q-objects/

@MostafaR - sure we could crush my entire codeblock down to one line if we wanted (see below). Its not very readable anymore at that level though. saying code isn't "Pythonic" just because it hadn't become reduced and obsfucated is silly. Readable code is king IMHO. Its also important to keep in mind the purpose of my answer was to show the reduce by an operator technique. The rest of my answer was fluff to show that technique in context to the original question.

result = MyModel.objects.filter(reduce(operator.or_, [Q(slug=s) for s in slug])) if hasattr(slug, "__iter__") else MyModel.objects.filter(slug=slug)

Upvotes: 4

schacki
schacki

Reputation: 9533

The code that you posted will not work in many ways (but I am not sure if it should be more pseudocode?), but from what I understand, this might help:

MyModel.objects.filter(slug__in=slug)

should do the job.

Upvotes: -1

MostafaR
MostafaR

Reputation: 3695

result = MyModel.objects.filter(slug__in=slug).all() if isinstance(slug, list) else MyModel.objects.filter(slug=slug).all()

Upvotes: 1

Pero
Pero

Reputation: 1441

I believe in this case you should use django's __in field lookup like this:

slugs = [ "snakes", "snake-s" ]
objects = MyModel.objects.filter(slug__in=slugs)

Upvotes: 0

Related Questions