Search code examples
djangotastypie

tastypie, GET/POST a field of a model?


I have a model like below.

class Checklist(models.Model):

    name = models.CharField(max_length=50, default="mylist")
    items = JSONField(default=get_default_checklist)
    user = models.ForeignKey(User, related_name='checklists')

For a given Checklist.id, I want to get items field only, so I created a resource for it.

class ChecklistItemsResource(ModelResource):

    def dehydrate_items(self, bundle):
        return json.dumps(bundle.obj.items, ensure_ascii=False)

    class Meta:
        queryset = models.Checklist.objects.all()
        resource_name = 'checklist_items'
        fields = ['items']

and I get the data with url /api/v1/checklist_items/8/?format=json
id=8 is actually id of checklist not id of checklist.items.

  • edit -

I think /api/v1/checklist/8/items/ looks better than /api/v1/checklist_items/8/.
To represent items field of checklist(id=8).

How do you create resource/url to fetch/update a specific field of a model?


Solution

  • You could use the prepend_urls hook to create a /items/ subresource for your Checklist resource. Add the following to your resource:

    from django.conf.urls import url
    from tastypie.bundle import Bundle
    from tastypie.utils import trailing_slash
    
    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/(?P<%s>\w[\w/-]*)/items%s$" % (self._meta.resource_name, self._meta.detail_uri_name, trailing_slash()), self.wrap_view('get_items'), name="api_get_items"),
        ]
    
    def get_items(self, request, **kwargs):
        pk = kwargs[self._meta.detail_uri_name]
        try:
            checklist = Checklist.objects.get(pk=pk)
        except Checklist.DoesNotExist:
            return self.create_response(request, {}, status=404)
    
        if request.method == 'GET':
            bundle = Bundle(request=request, obj=checklist)
            bundle.data['items'] = self._meta.fields['items'].dehydrate(bundle)
            if hasattr(self, 'dehydrate_items'):
                bundle.data['items'] = self.dehydrate_items(bundle)
    
            return self.create_response(request, bundle)
        elif request.method == 'PATCH':
            data = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json'))
            checklist.items = data
            checklist.save()
            return self.create_response(request, {})
    

    To update the items field, send a PATCH request to the /items/ endpoint with new serialized new value in the body. This view can be easily extended for general case.