I’ve been working a whole lot outside of my job, mostly writing Python and working with Django. I don’t have much energy for a real blog post about something awesome, but I do have a tip to share. Advanced “pythonistas” won’t be impressed, but I haven’t seen this documented prominently anywhere, so I’ll toss it up anyway.
As we all know, Python supports keyword arguments, and the Django ORM takes full advantage of this. When doing lookups, the ORM parses keyword parameters in order to determine what SQL query to execute. A typical ORM call will look like this:
all_oatmeal = Cookie.objects.filter(cookie_type='oatmeal')That’s very cool and expressive. However, what if our search criteria depend somehow on user input? For example, what if we have a search form with multiple fields, but only want to search by the fields that a user entered something into.
We could have a series of convoluted if/else statements to determine which variables were set and have a corresponding .filter() call for each possibility, but that would be dumb, convoluted, and hard to read later. Also, dumb.
Instead, we can use an alternative way of passing keyword arguments provided by Python (details here): putting ** in front of a dictionary being passed to a function makes Python unpack the dictionary and pass the pairs as keyword arguments to the function. Using that technique, we can arbitrarily construct a dictionary of the search parameters, then pass it to a single .filter() call at the bottom.
An over-simplified example, in which I assume that our form fields match up exactly with model properties
for key in form_data: if form_data[key]=='': del form_data[key] wanted_cookies = Cookie.objects.filter(**form_data)I’m sure there’s a more elegant way to do the empty value stripping too, but that’s not our focus (comments on the subject are welcome, though, for to make me smarter). The point is this: this technique allows for very clean, easy to read, efficient code.
Creating model instances
cookie_data = {
'cookie_type': 'oatmeal',
'cookie_size': '3in',
'cookie_touched': True
}
c = Cookie(**cookie_data)
c.save()
Obviously, this applies to more than just Django – there are many many use cases where this trick can come in handy. Enjoy!