Django Tastypie使用PATCH或PUT请求进行多对多(自我)字段更新?

时间:2013-04-13 11:15:38

标签: python django api rest tastypie

我有这个型号:

class UserSub(models.Model):
    user = models.OneToOneField(User, related_name='userSub')
    amigos = models.ManyToManyField('self', null=True)
    title = models.TextField()

导入的Django用户模型。

以下资源:

class UserResource(ModelResource):
    usersub = fields.OneToOneField('test.api.UserSubResource', attribute = 'personal', related_name='user', full=True, null=True)    
    class Meta:
        object_class = User
        fields = ['username', 'first_name', 'last_name', 'password', 'email']
        detail_allowed_methods = ['get', 'post', 'put']
        authentication = Authentication()
        authorization = Authorization()
        queryset = User.objects.all()
        resource_name = 'users'
        excludes = ['id']

class UserSubResource(ModelResource):
    user = fields.OneToOneField('test.api.UserResource', attribute = 'user', related_name = 'userSub')
    amigos= fields.ToManyField('test.api.UserSubResource', attribute = 'amigos', null=True)      
    class Meta:
        object_class = UserSub
        fields = ['title']
        detail_allowed_methods = ['get', 'post', 'put', 'patch']
        authentication = Authentication()
        authorization = Authorization()
        always_return_data = True
        queryset = UserSub.objects.all()
        resource_name = 'usersub'
        excludes = ['id'] 

我正在尝试更新特定用户的amigos值。我的数据是:

usersub_json: {"amigos":["/api/v1/usersub/9/","/api/v1/usersub/8/"]}

$.ajax({
        url : 'http://127.0.0.1:8000' + usersub_uri,
                        type : 'PUT',
                        contentType : 'application/json',
                        data : usersub_json,
                        dataType : 'json',
                        processData : false,
                        error : function(http) {
                            if (http.responseText != "") {
                                alert(http.responseText);
                            }
                        }
                    })

我从PUT请求中收到“ 202 ACCEPTED ”,并且没有更新amigos。

来自PATCH请求的“ 202 ACCEPTED ”,并且amigos不会更新。

如果我在创建usersub时在第一个post请求中添加了amigos,它会成功地将它们添加到数据库中。但是如果我使用PUT或PATCH向阵列添加更多内容,则不会更新。

1 个答案:

答案 0 :(得分:2)

我不能确定它和你的情况一样,但我发现了我的问题。

让我稍微修改你的例子以反映我遇到的情况:

class UserResource(ModelResource):
    usersubs = fields.ToManyField('test.api.UserSubResource', attribute = 'usersubs', full=True, null=True)
    specialUsersub = fields.ToOneField('test.api.UserSubResource', attribute = 'special_user_sub', full=True, null=True) 
    class Meta:
        object_class = User
        fields = ['username', 'first_name', 'last_name', 'password', 'email']
        detail_allowed_methods = ['get', 'post', 'put']
        authentication = Authentication()
        authorization = Authorization()
        queryset = User.objects.all()
        resource_name = 'users'
        excludes = ['id']

class UserSubResource(ModelResource):
    amigos= fields.ToManyField('test.api.UserSubResource', attribute = 'amigos', null=True)      
    class Meta:
        object_class = UserSub
        fields = ['title']
        detail_allowed_methods = ['get', 'post', 'put', 'patch']
        authentication = Authentication()
        authorization = Authorization()
        always_return_data = True
        queryset = UserSub.objects.all()
        resource_name = 'usersub'
        excludes = ['id']

和请求:

PATCH /users/1/
{ "specialusersub" : { "id" : 3, "amigos" : ["/api/v1/usersub/9/","/api/v1/usersub/8/"] } }

在我的情况下,这个问题是由于在父级资源也存在于顶层的ToMany关系中时尝试修补嵌套了两层深度的ToMany资源。由于嵌套以及资源上字段的顺序,操作顺序如下:

  1. 将用户子集合成bundle(及其嵌套关系 - 从DB加载,在我们的例子中为空)
  2. 将specialUsersub水合成束(及其嵌套关系 - 包含在请求数据中)
  3. 保存specialUsersub(此处正确保存嵌套资源)
  4. [此时tastypie应该检查是否有任何水合资源被保存并且再补充适当的捆绑部分,但事实并非如此:]
  5. 保存usersubs(如果specialUsersub上的资源也存在于usersubs中,那么之前保存的内容将被在步骤1中用户子集合时加载的陈旧数据覆盖)
  6. 更确切地说,因为tastypie故意清除所有m2m关系,然后用存储在bundle中的内容重新填充它们,过时的数据会破坏新数据,3中创建的amigos被删除并替换为[]空列表。装入1。

    我还在测试,但我认为解决方案/黑客是确保您包含更新的嵌套资源 whereever 您的tastypie资源可能期望它:

    PATCH /users/1/
    { "usersubs" : [{ "id" : 3, "amigos" : ["/api/v1/usersub/9/","/api/v1/usersub/8/"] }], "specialusersub" : { "id" : 3, "amigos" : ["/api/v1/usersub/9/","/api/v1/usersub/8/"] } }
    

    显然这并不理想。如果我想出一个更合适的解决方案,我会告诉你的。