Search code examples
djangotastypie

Altering incoming Django url queries using tastypie : handling foreign key traversal on the backend


So we've got a Django/tastypie server going that has the following (simplified) model. If I remove our alter_detail_data_to_serialize:

{
   "release": false, 
   "resource_uri": "/api/packages/1", 
   "id": 1, 
   "branch": {
      "resource_uri": "/api/branches/1", 
      "id": 1, 
      # ... more bits the client doesn't need to know about
      "version": "0.1"
   }, 
   "revision": "72"
}

With the alter, it becomes:

{
   "release": false, 
   "branch": "0.1", 
   "revision": "72"
}

Which is what we want to work with through the API: It removes the foreign key traversal to simplify the JSON and do any CRUD without issues: supplying a version is sufficient to identify the branch. The issue is, to query this, requires /api/packages?branch__version=1.0, where this not intuitive and exposes the structure of the underlying database. We'd prefer to be able to query: /api/packages?branch=1.0 and handle the foreign key traversal on the backend.

alter_detail_data_to_serialize and alter_deserialized_detail_data allow me to interface with the simplified JSON and do any non-searching CRUD without issues, but is it possible to allow a /api/packages?branch=1.0 query and have the django/tastypie server correct that to /api/packages?branch__version=1.0, hiding the database structure?

Some additional code that might be relevant:

class PackageResource(ModelResource):
    branch = fields.ForeignKey(BranchResource, 'branch', full=True)

    class Meta:
        queryset = Packages.objects.all()
        resource_name = 'packages'
        collection_name = 'packages'

    def alter_detail_data_to_serialize(self, request, data):
        data.data['branch'] = data.data['branch'].data['version']
        return data

Branch Resource:

class BranchResource(ModelResource):
    class Meta:
        queryset = Branches.objects.all()
        resource_name = 'branches'
        collection_name = 'branches'

Solution

  • In the object resource, you can add something like this:

    class PackageResourse(ModelResource):
        version = fields.CharField( attribute = 'branch__version' )
        class Meta:
          resource_name='package'
    

    What this is doing it making the PackageResource have a variable that is the same as its foreign key's variable. Now you can use api/packages?version=1.0 on the PackageResource.