使用 PATCH 或 PUT 请求更新 Django Tastypie 多对多(自)字段? [英] Django Tastypie Many to Many (self) field update using a PATCH or PUT request?

查看:19
本文介绍了使用 PATCH 或 PUT 请求更新 Django Tastypie 多对多(自)字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个模型:

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

导入的 Django 用户模型.

Imported Django User Model.

以及以下资源:

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 值.我的数据是:

I am trying to update amigos values for a specific user. My data is:

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",并且朋友没有更新.

I am getting "202 ACCEPTED" from PUT request, and the amigos are not updated.

和来自 PATCH 请求的202 ACCEPTED",并且朋友没有更新.

And "202 ACCEPTED" from PATCH request, and the amigos are not updated.

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

If I add the amigos in the first post request when creating a usersub, it adds them to the database successfully. But doesn't update if I add more to the array using PUT or PATCH.

推荐答案

我不确定它是否与您的情况相同,但我发现了我的问题.

I can't be sure it's the same as your situation, but I found my problem.

让我稍微修改一下您的示例以反映我遇到的情况:

Let me modify your example slightly to reflect the situation I encountered:

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 资源引起的.由于嵌套和资源上字段的顺序,操作的顺序是这样的:

In my case this problem was caused by trying to patch a ToMany resource nested two levels deep when the parent resource also existed in a ToMany relationship at the top level. Because of the nesting and because of the order of fields on the resource, the order of operations happened like this:

  1. 将用户订阅组合成包(及其嵌套关系 - 从数据库加载,在我们的示例中为空)
  2. 将 specialUsersub 结合到包中(及其嵌套关系 - 包含在请求数据中)
  3. 保存 specialUsersub(此处正确保存了嵌套资源)
  4. [此时,tastypie 应该检查其是否有任何水合资源被保存并重新水合包的适当部分,但它没有,所以:]
  5. 保存 usersubs(如果 specialUsersub 处的资源也存在于 usersubs 中,那么先前保存的内容将被在步骤 1 中对 usersubs 进行水合时加载的陈旧数据覆盖)

更准确地说,因为tastypie在用存储在包中的内容重新填充它们之前故意清除所有m2m关系,陈旧的数据破坏了新数据,在3中创建的朋友被删除并替换为[]空列表加载于 1.

To be more precise, because tastypie deliberately clears all m2m relationships before repopulating them with what's stored in the bundle, the stale data clobbers the new data, the amigos created in 3 are deleted and replaced with the [] empty list that was loaded in 1.

我仍在测试,但我认为解决方案/技巧是确保您包含更新的嵌套资源任何您的美味派资源可能期望它:

I'm still testing, but I think the solution/hack is to ensure that you include the updated nested resource whereever your tastypie resource might be expecting it:

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/"] } }

显然这并不理想.如果我想出更合适的解决方案,我会通知您.

Obviously that's not ideal. I'll let you know if I come up with a more appropriate solution.

这篇关于使用 PATCH 或 PUT 请求更新 Django Tastypie 多对多(自)字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆