tags:

views:

275

answers:

2

As you may be able to tell from my questions, I'm new to both python and django. I would like to allow dynamic filter specifications of query sets from my templates using **kwargs. I'm thinking like a select box of a bunch of kwargs. For example:

  <select id="filter">
    <option value="physician__isnull=True">Unassigned patients</option>
  </select>

Does django provide an elegant solution to this problem that I haven't come across yet?

I'm trying to solve this in a generic manner since I need to pass this filter to other views. For example, I need to pass a filter to a paginated patient list view, so the pagination knows what items it's working with. Another example is this filter would have to be passed to a patient detail page so you can iterate through the filtered list of patients with prev/next links.

Thanks a bunch, Pete

Update:

What I came up with was building a FilterSpecification class:

class FilterSpec(object):
def __init__(self, name, *args):
 super(FilterSpec, self).__init__()
 self.name = name
 self.filters = []

 for filter in args:
  self.add(filter)

def pickle(self):
 return encrypt(pickle.dumps(self))

def add(self, f):
 self.filters.append(f)

def kwargs(self):
 kwargs = {}
 for f in self.filters:
  kwargs = f.kwarg(**kwargs)
 return kwargs

def __unicode__(self):
 return self.name



class Filter(object):
def __init__(self, key, value):
 super(Filter, self).__init__()
 self.filter_key = key
 self.filter_value = value

def kwarg(self, **kwargs):
 if self.filter_key != None:
  kwargs[self.filter_key] = self.filter_value
  return kwargs

I then can filter any type of model like this:

filterSpec = FilterSpec('Assigned', Filter('service__isnull', False)))
patients = Patient.objects.filter(**filterSpec.kwargs())

I pass these filterSpec objects from the client to server by serializing, compressing, applying some symmetric encryption, and url-safe base-64 encoding. The only downside is that you end up with URLs looking like this:

http://127.0.0.1:8000/hospitalists/assign_test/?filter=eJwBHQHi_iDiTrccFpHA4It7zvtNIW5nUdRAxdiT-cZStYhy0PHezZH2Q7zmJB-NGAdYY4Q60Tr_gT_Jjy_bXfB6iR8inrNOVkXKVvLz3SCVrCktGc4thePSNAKoBtJHkcuoaf9YJA5q9f_1i6uh45-6k7ZyXntRu5CVEsm0n1u5T1vdMwMnaNA8QzYk4ecsxJRSy6SMbUHIGhDiwHHj1UnQaOWtCSJEt2zVxaurMuCRFT2bOKlj5nHfXCBTUCh4u3aqZZjmSd2CGMXZ8Pn3QGBppWhZQZFztP_1qKJaqSVeTNnDWpehbMvqabpivtnFTxwszJQw9BMcCBNTpvJf3jUGarw_dJ89VX12LuxALsketkPbYhXzXNxTK1PiZBYqGfBbioaYkjo%3D

I would love to get some comments on this approach and hear other solutions.

+1  A: 

Rather than face the horrible dangers of SQL injection, why not just assign a value to each select option and have your form-handling view run the selected query based on the value.

Passing the parameters for a DB query from page to view is just asking for disaster. Django is built to avoid this sort of thing.

Gabriel Hurley
This filter will be needed in multiple views. I'm trying to solve this problem in a generic manner.
slypete
A: 

Concerning your update: FilterSpecs are unfortunately one of those (rare) pieces of Django that lack public documentation. As such, there is no guarantee that they will keep working as they do.

Another approach would be to use Alex Gaynor's django-filter which look really well thought out. I'll be using them for my next project.

piquadrat
Thanks piquadrat. Are you aware if django-filter provides any security to ensure unspecified filters aren't allowed?
slypete
Unfortunately, there is zero security with Alex's implementation. I can choose any custom filter that I'd like.
slypete