Search code examples
javascriptdjangotastypiex-editable

tastypie and x-editable using patch


I almost have x-editable working with the django API built with tastypie thanks to various other answers on stackoverflow, but not quite.

Here is the html:

 <a href="#" id="field_name" class="editable"
                                 data-name="name"
                                 data-pk="{{ object.id }}"
                                 data-value="{{ object.name }}"
                                 data-title="Meeting Name">
                            {{ object.name }}</a>

and the javascript:

   $('.editable').on('init', function(e, edt) {
        edt.options.url = '/api/v1/update_meeting/' +edt.options.pk;
    });
    $('.editable').editable({
        mode: 'inline',
        ajaxOptions: {
            type: 'PATCH'
        },


        success: function(response, newValue) {

            // nothing to do
        }

    });

And the tastypie resource:

class UpdateMeetingResource(ModelResource):

class Meta:
    queryset = Meeting.objects.all()
    resource_name = 'update_meeting'
    limit = 0
    include_resource_uri = False
    list_allowed_methods = ['get','patch',]
    detail_allowed_methods = ['get', 'patch']
    serializer = urlencodeSerializer()
    authentication = Authentication()
    authorization = Authorization()

My only problem is that the field name gets updated with "name" and not the value in data-value. Before I put in the data-name attribute, it was setting the value to "field_name".

I could fix this by simply changing the patch-detail method in my tastypie resource, but it would be nice to get it working without doing that.


Solution

  • So the problem was that the patch being sent was a key value pair and that was not being recognised by tastypie, but a quick modifiation to hydrate fixes it. Maybe not the best solution but here is what is working for me:

    The html:

        <a href="#" id="name" class="editable editable_default_setup"
          data-title="Name"
          data-pk="{{ object.pk }}"
          data-value="{{ object.name }}"
          data-placeholder="Meeting Name" >
          {{ object.name }}</a>
    

    The javascript:

    $('.editable').on('init', function(e, edt) {
        edt.options.url = '/api/v1/meeting/' + {{ object.id }};
    });
    
    $.fn.editable.defaults.ajaxOptions = {type: "PATCH"};
    
    $('.editable_default_setup').editable();
    

    Setting up the resource:

     class Meta:
        queryset = Meeting.objects.all()
        include_resource_uri = False
        resource_name = 'meeting'
        limit = 100
        allowed_methods = ['post','put','get','options','patch', 'delete']
        detail_allowed_methods = ['patch']
        authentication = Authentication()
        authorization = Authorization()
        serializer = urlencodeSerializer()
        always_return_data=True
    

    The important bit, Modification to the tastypie resource:

    def hydrate(self, bundle):
    
        if bundle.request.method == "PATCH":
            # data is supplied by x-editable in format {u'pk': u'1170', u'name': u'owner', u'value': u'5', u'format': u'json'}
            # apply this value to the obj and return
    
            field_name = bundle.data['name']
            field_value = bundle.data['value']
    
            # the use of name is unfortunate as it can override a field called name, so put it back to original value unless updating it
            # do the same with value, just in case
    
            bundle.data['name'] = getattr(bundle.obj, 'name', None)
            bundle.data['value'] = getattr(bundle.obj, 'value', None)
    
            # now set the attribute field_name to field_value so object will update
            bundle.data[field_name] = field_value
            setattr(bundle.obj, field_name, field_value)
    
    
     return bundle