Tastypie Advanced Filtering: Complex lookups with Q objects

1,852 views
Skip to first unread message

nganda

unread,
Apr 2, 2012, 10:42:32 AM4/2/12
to django-...@googlegroups.com
Hi Guys,

I have a basic model like:

class Business(models.Model):
    name = models.CharField(max_length=200, unique=True)
    email = models.EmailField()
    phone = models.CharField(max_length=40, blank=True, null=True)
    description = models.TextField(max_length=500)

I need to execute a complex query on the above model like:

qset = (
                    Q(name__icontains=query) |
                    Q(description__icontains=query) |
                    Q(email__icontains=query)
                    )
results = Business.objects.filter(qset).distinct()

I have tried the following using tastypie with no luck:

 def build_filters(self, filters=None):
        if filters is None:
            filters = {}
        orm_filters = super(BusinessResource, self).build_filters(filters)

        if('query' in filters):
            query = filters['query']
            print query
            qset = (
                    Q(name__icontains=query) |
                    Q(description__icontains=query) |
                    Q(email__icontains=query)
                    )
            results = Business.objects.filter(qset).distinct()
            orm_filters = {'query__icontains': results}

        return orm_filters

and in class Meta I have filtering set as:

filtering = {
            'name: ALL,
            'description': ALL,
            'email': ALL,
            'query': ['icontains',],
        }

Any ideas to how I can tackle this? 

Thanks 
 - Newton


Jeff Baier

unread,
Apr 3, 2012, 9:43:59 AM4/3/12
to django-...@googlegroups.com
Override or extend obj_get_list. This returns a queryset. I haven't tried it but I assume any valid django ORM filtering will work here. 

nganda

unread,
Apr 4, 2012, 10:18:14 PM4/4/12
to django-...@googlegroups.com
Hi Jeff,
Thanks by the way, I see what you mean.
For example I would write something like:

def get_object_list(self, request, *args, **kwargs):
        return Business.objects.filter(Q(name__icontains=query) | Q(description__icontains=query))

Doesn't this mean I have to create 2 resources for Business, one to handle the normal business objects, the other to handle the
above filtering maybe for search?
Is that good practice?

-Newton

Jeff Baier

unread,
Apr 5, 2012, 9:47:52 AM4/5/12
to django-...@googlegroups.com
Actually after reading back through your posts I think apply_filters might be the better place for it. 

My assumptions for the code below are that you have a resource named BusinessResource, that is a ModelResource for Business model you put in your first post. And that sometimes you want to just get results from the api at /api/v1/business/, but sometimes want to perform a query like /api/v1/business/?query=verizon 


def apply_filters(self, request, applicable_filters):
    base_object_list = super(BusinessResource, self).apply_filters(request, applicable_filters)
    
    query = request.GET.get('query', None)
    if query:
        qset = (
            Q(name__icontains=query) |
            Q(description__icontains=query) |
            Q(email__icontains=query)
        )
        base_object_list = base_object_list.filter(qset).distinct()
    
    return base_object_list

nganda

unread,
Apr 7, 2012, 4:08:21 PM4/7/12
to django-...@googlegroups.com
Hi Jeff,

I tried apply_filters and it worked like a charm :).
Thanks very much, you have really helped me.

Newton
Reply all
Reply to author
Forward
0 new messages