I'm new to Django, Tastypie and asking questions here.
I've got a Django application with an API using Tastypie. If I make a GET
request to /api/v1/ou/33/
, my API returns the object with the id==33, which is ok.
{
"child_ou_uri": "/api/v1/ou/33/child_ou/",
"displayname": "Mother",
"id": 33,
"inherit": true,
"name": "Mother",
"resource_uri": "/api/v1/ou/33/"
}
The thing is, I'm trying to extend the API so that it returns related objects via the child_ou_uri
URI from the above object. The children are the same type of objects as their parents. The model has an attribute parent_id
pointing to the pk
of its parent.
My OuResource
looks like this:
class OuResource(ModelResource):
class Meta:
queryset = OU.objects.all()
resource_name = 'ou'
list_allowed_methods = ['get']
detail_allowed_methods = ['get']
filtering = {
'name': ['icontains'],
}
authentication = SessionAuthentication()
authorization = OperatorLocationAuthorization()
def get_child_ou(self, request, **kwargs):
self.method_check(request, ['get', ])
ous = OuResource().get_list(request, parent_id=kwargs['pk'])
return ous
def prepend_urls(self):
return [
url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/child_ou%s$' % (self._meta.resource_name, '/'),
self.wrap_view('get_child_ou'),
name='api_get_child_ou')
]
def dehydrate(self, bundle):
kwargs = dict(api_name='v1', resource_name=self._meta.resource_name, pk=bundle.data['id'])
bundle.data['child_ou_uri'] = reverse('api_get_child_ou', kwargs=kwargs)
return bundle
When I navigate to /api/v1/ou/33/child_ou/
I'd like to get the list of child objects which have their attribute parent_id
set to 33, but instead I get ALL of my objects without any filtering at all, equivalent to me navigating to /api/v1/ou/
.
{
"meta": {
"limit": 20,
"next": "/api/v1/ou/?offset=20&limit=20&format=json",
"offset": 0,
"previous": null,
"total_count": 29
},
"objects": [
{
"child_ou_uri": "/api/v1/ou/33/child_ou/",
"displayname": "Mother",
"id": 33,
"inherit": true,
"name": "Mother",
"resource_uri": "/api/v1/ou/33/"
},
{
"child_ou_uri": "/api/v1/ou/57/child_ou/",
"displayname": "Mothers 1st child",
"id": 57,
"inherit": true,
"name": "Child 1",
"resource_uri": "/api/v1/ou/57/"
},
{
"child_ou_uri": "/api/v1/ou/58/child_ou/",
"displayname": "Mothers 2nd child",
"id": 58,
"inherit": true,
"name": "Child 2",
"resource_uri": "/api/v1/ou/58/"
}
]
}
What am I missing here?
[SOLUTION]
Gareth's answer put me on the right track. I altered my OuResource to look like below. This allows me to navigate to a url like /api/v1/ou/33/child_ous/
which returns a custom json of the child objects.
class OuResource(ModelResource):
class Meta:
queryset = OU.objects.all()
resource_name = 'ou'
list_allowed_methods = ['get']
detail_allowed_methods = ['get']
filtering = {
'name': ['icontains'],
}
authentication = SessionAuthentication()
authorization = OperatorLocationAuthorization()
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/(?P<ou_id>\d+)/child_ous%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('child_ous'), name="api_child_ous"),
]
def child_ous(self, request, **kwargs):
self.method_check(request, allowed=['get'])
self.is_authenticated(request)
self.throttle_check(request)
ous = list(OU.objects.filter(parent_id=kwargs['ou_id']))
data = []
for x in ous:
data.append({
'id' : x.id,
'name' : x.name,
'parent_id' : x.parent_id
})
return JsonResponse(data, safe=False)
First, check out the tastypie documentation on creating a search.
It'd be easier to do this without nesting, e.g. /api/v1/ou_related/?to=58, but nesting may be desireable for its expressiveness.
For nested search with pagification, look at creating another resource, OuSearchResource. That resource would override authorized_read_list (and maybe get_list) to pass along the necessary details.