views:

476

answers:

2

Before the question, the background:

I am putting the finishing touches on an API I have written for a Django app utilizing django-piston. The API is able to search by request or IP address which are Request or IPAddress instances respectively. Each request can have 1 or more IPAddress associated with it.

So, for example I have an API call that will show all IPAddress objects matching an activity status of "active", "inactive", or "all" (for either). The Request to which each IPAddress instance is associated is available as IPAddress.request.

The problem I am having is that Request.inputter is a foreign key to the User instance of the person who provisioned the request. When my results are returned from the handler I have created for this API call, all fields from the User instance are displayed, including password.

This is bad; I do not want this.

So here is my handler:

class SearchByIPStatusHandler(BaseHandler):
    model = IPAddress
    allowed_methods = ('GET',)
    anonymous = AnonymousIPHandler

    def read(self, request, status):
        """
        Returns IP addresses based on activity status.  
        Status: 'active', 'inactive', 'all'

        """
        if status == 'all':
            return self.model.objects.all()
        else:
            active = True if (status=='active') else False
            return self.model.objects.filter(active=active)

And here is an example of the results from /api/show/all/:

<response>
  <resource>
    <updated>2010-02-05 17:08:53.651729</updated>
    <expires>2010-02-12 17:08:23</expires>
    <created>2010-02-05 17:08:53.625318</created>
    <nexthop>255.255.255.255</nexthop>
    <netmask>255.255.255.254</netmask>
    <address>2.4.6.80/31</address>
    <active>True</active>
    <id>4</id>
    <request>
      <updated>2010-02-05 17:08:53.382381</updated>
      <created>2010-02-05 17:08:53.382313</created>
      <expires>2010-02-12 17:08:23</expires>
      <incident>20100212-badthings-01</incident>
      <reason>bad things happened</reason>
      <inputter>
        <username>jathan</username>
        <first_name>Jathan</first_name>
        <last_name>McCollum</last_name>
        <is_active>True</is_active>
        <email>[email protected]</email>
        <is_superuser>True</is_superuser>
        <is_staff>True</is_staff>
        <last_login>2010-02-05 18:55:51.877746</last_login>
        <password>[ENCRYPTED STRING I REDACTED]</password>
        <id>1</id>
        <date_joined>2010-01-28 09:56:32</date_joined>
      </inputter>
      <requester>joeuser</requester>
      <active>True</active>
    </request>
  </resource>
</response>

All I really want in the results is the inputter.username, not all of the other stuff. I have tried various iterations of implementing an exclude attribute on the handler to no avail. If I just skip the entire request field, that works fine, like so:

In handler:

exclude = ('request', )

Which results in:

<response>
  <resource>
    <updated>2010-02-05 17:08:53.651729</updated>
    <expires>2010-02-12 17:08:23</expires>
    <created>2010-02-05 17:08:53.625318</created>
    <nexthop>255.255.255.255</nexthop>
    <netmask>255.255.255.254</netmask>
    <address>2.4.6.80/31</address>
    <active>True</active>
    <id>4</id>
  </resource>
</response>

But these results are also not what I want.

So, finally, my question:

How can I exclude nested fields from handler results? Is it even possible?

I have tried various iterations of the following, all of which either have no result, or unintended results:

# try to exclude request.inputter
exclude = ( ('request', ('inputter', ), ) )

# try to exclude request.inputter.password
exclude = ( ('request', ('inputter', ('password', ) ) ) ) 

I assume that I am misunderstanding or misusing the way field exclusions are done in this context, so any enlightenment on this topic is greatly appreciated.

Thanks in advance for your responses!

+1  A: 

Can you try using include instead of exclude? E.g.

include = (('request', ('inputter', ('username', 'therestofthefields'))))

I don't remember if I wrote exclude to be as versatile as include.

Also, the django-piston Google group is where we discuss most things, you may have more success asking this question there.

jespern
Thanks for chiming in, Jesper. I will dupe this on the mailing list.
jathanism
+1  A: 

You can get the desired result by specifying the desired fields via the handler's fields = clause.

Model fields coming from foreign keys can be specified like this:

('foreign_model_field', ('nested_field1', 'nested_field2'))

In your case, the following should work (some of your fields left out for brevity):

fields = ('updated', 'expires', 'created', 
    ('request', ('incident', 'reason', ('inputter', ('username',)))))
flanth
That does indeed work. Thanks for the response! More tedious than what I was hoping for (especially when I'll invetiably have to duplicate this across multiple handlers), but a solution is a solution!
jathanism