django-tastypie / django-tastypie

Creating delicious APIs for Django apps since 2010.
http://tastypieapi.org/
Other
3.92k stars 1.17k forks source link

Missing form data from kwargs when validating new instance with PUT request #1614

Open goffioul opened 4 years ago

goffioul commented 4 years ago

I noticed a regression in my code when upgrading 0.14.3 (I was previously using 0.14.2). I tracked it down this (I believe) this change: 2ec95c3bd5366290647699f08525303dce6f68b8. The bottom line is that this change pops detail_uri_name from kwargs before bundle.data is updated with it, so it's not part of the bundle data anymore. Later on, I have a resource with a ModelForm validation, and the form validation fails, because the data is missing.

Conceptually, my code is along those lines:

class TestModel(models.Model):
    test_field = models.CharField(unique=True) 

class TestModelForm(forms.ModelForm):
    class Meta:
        model = TestModel

class TestModelResource(ModelResource):
    class Meta:
        detail_uri_name = 'test_field'
        queryset = TestModel.objects.all()
        resource_name = 'test'

With 0.14.2, I was able to send a PUT request to /test/foobar and have the TestModel instance created with the the expected test_field value. With 0.14.3, it returns a bad request status (400), because TestModelForm is missing the data for test_field. The reason is that it has been stripped from the bundle data due to the change mentioned above.

goffioul commented 4 years ago

Further analysis shows that there may be other parts of my code at play (and I think I found a workaround), so feel free to close the bug if you believe it's invalid. However, I still think there's something odd in the put_detail logic, as both the update and create code path share the same bundle, and one impacts the other. If the target object does not exist yet, then the update code path will still alter the bundle's data, but will have popped detail_uri_name before updating it. The create code path then uses that bundle, in particular the bundle data is used in the form validation (as the instance does not exist, FormValidation will use bundle.data as form's data).