I am currently writing a project that uses Django w/ Django-Rest-Framework on the backend and Ember.js/Ember-data on the front-end.
I am looking to pass queries back from my ember app to my django api in this format
http://myurl.com/application/api/model/?parameter=X
where parameter is a field on the model being queried and X is a value to search for.
something loosely like this should be the resulting query
queryset = Model.objects.filter(**request.QUERY_PARAMS.dict())
where QUERY_PARAMS.dict() is Django syntax that gives a dictionary of the format
{parameter:X}
** converts the dict into keyword arguments as are expected by Django.
Thus the line above is effectively:
queryset = Model.objects.filter(parameter=X)
I have this working already using custom views and a custom mixin but I am concerned that my query handling implementation may be a bit naive and this strikes me as an extremely common pattern.
I am wondering if there are libraries out there for Django or perhaps some Django internals I’m not fully understanding that would handle these relatively common queries for me without my custom queryset code?
Any pointers in the right direction would be sincerely appreciated.
Steve Kane
EDIT:
def get_integer_queryset(self, query, queryset):
#stringify the first entry in query.keys (query is request.QUERY_PARAMS)
query_key = str(query.keys()[0])
#split the string into individual strings since the request object dict
#contains only a string of numbers and not an actual array (see below)
#query = {'parameter':'1,2,3,4'} becomes {'parameter':['1','2','3','4']}
query_values = query.get(query_key, None).split(",")
#construct two dicts. One handles integers and the other handles "null"
#all the code below is required because Django does not seem to handle "null"
#as a valid query to a field that is type "integer"
#as a side note, I think this is poor and create annoying work...i would love
#to be wrong here
#the Q objects are required in order to compose a query of both integers and
#the string "null"
query_vals_no_null = {query_key+"__in": []}
optional_null_dict = {}
for value in query_values:
if value == "null" or value == "None":
optional_null_dict[query_key+"__isnull"] = True
else:
query_vals_no_null[query_key+"__in"].append(value)
return queryset.filter( Q(**query_vals_no_null) |
Q(**optional_null_dict) )
This is my primary method taken from my custom view that handles integer querys. I inserted comments to clarify what is happening. Let me know if this helps or looks familiar/terrible/awesome/somewhat mildly okish.
Steve
django-filter (and REST framework’s corresponding django-filter based filter backend) really is the closest out-of-the-box app to what you’re looking for, but as you’ve found it doesn’t quite support the use case you need, notably because:
null/Nonekeys in querystring.__instyle lookups using comma delimiting.(I could be wrong about either/both of the above, but that’s how it appears to me from a look around the source/docs)
Which means your options are probably:
django-filter.I don’t think any of the options in (3) will do quite what you need, although you might want to have a quick dig into tastypie and piston, and see if they provide filtering implementations that do what you need, and base something of those if it does.
There’s also a closed pull request for an alternate filter solution for REST framework, which looks like it does support you
__instyle filtering. If that seems to do what you need then it’d be worth commenting against the ticket, and we could consider re-opening it with a view to providing another filter backend in REST framework. (Ideally as a 3rd party filter backend.)If you continue with using your own filter solution as you’ve already started doing, and end up with something more comprehensive, it’d be worth mentioning it on the REST framework group, so other folks can use it, and so we can consider if it’s worth pulling it together into a more easily re-useable 3rd party package.
Let me know how you get on, either on the group, by editing this question with an update.