Django Rest Framework部分更新

时间:2016-12-12 22:26:30

标签: django django-rest-framework

我试图用Django Rest Framework来实施partial_update,但我需要澄清一下,因为我被卡住了。

  1. 为什么我们需要指定partial = True?
    根据我的理解,我们可以轻松更新partial_update方法内的Demo对象。这是什么目的?

  2. 序列化变量内部是什么?
    serialized方法中partial_update变量的内部是什么?那是一个Demo对象吗?在幕后调用什么功能?

  3. 如何完成此处的实施?
  4.   

    视图集

    class DemoViewSet(viewsets.ModelViewSet):
        serializer_class = DemoSerializer
    
        def partial_update(self, request, pk=None):
            serialized = DemoSerializer(request.user, data=request.data, partial=True)
            return Response(status=status.HTTP_202_ACCEPTED)
    
      

    串行

    class DemoSerializer(serializers.ModelSerializer):
        class Meta:
            model = Demo
            fields = '__all__'
    
        def update(self, instance, validated_data):
            print 'this - here'
            demo = Demo.objects.get(pk=instance.id)
            Demo.objects.filter(pk=instance.id)\
                               .update(**validated_data)
            return demo
    

5 个答案:

答案 0 :(得分:59)

我有与你之前相同的问题,但是当我深入研究rest_framework的源代码时,我得到了以下结论,希望它会有所帮助:

问题1)

此问题与HTTP verbs有关。

PUT :PUT方法用请求有效负载替换目标资源的所有当前表示。

PATCH :PATCH方法用于对资源进行部分修改。

一般来说,partial用于检查客户端向视图提交数据时是否需要模型中的字段进行字段验证。

例如,我们有Book这样的模型,请注意nameauthor_name字段都是强制(不是null& not空)。

class Book(models.Model):
    name = models.CharField('name of the book', max_length=100)
    author_name = models.CharField('the name of the author', max_length=50)

# Create a new instance for testing
Book.objects.create(name='Python in a nut shell', author_name='Alex Martelli')

对于某些情况,我们可能只需要更新模型中的部分字段,例如,我们只需更新name中的Book字段。因此,对于这种情况,客户端只会向视图提交带有新值的name字段。客户提交的数据可能如下所示:

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

但您可能已注意到我们的模型定义不允许author_name为空。因此,我们必须使用 partial_update 而不是 update 。因此,其余框架不会对请求数据中缺少的字段执行字段验证检查

出于测试目的,您可以为updatepartial_update创建两个视图,您将更加了解我刚才所说的内容。

实施例

views.py
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import UpdateModelMixin
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book


class BookUpdateView(GenericAPIView, UpdateModelMixin):
    '''
    Book update API, need to submit both `name` and `author_name` fields
    At the same time, or django will prevent to do update for field missing
    '''
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class BookPartialUpdateView(GenericAPIView, UpdateModelMixin):
    '''
    You just need to provide the field which is to be modified.
    '''
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)
urls.py
urlpatterns = patterns('',
    url(r'^book/update/(?P<pk>\d+)/$', BookUpdateView.as_view(), name='book_update'),
    url(r'^book/update-partial/(?P<pk>\d+)/$', BookPartialUpdateView.as_view(), name='book_partial_update'),
)

要提交的数据

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

当您将上述json提交到/book/update/1/时,HTTP_STATUS_CODE = 400会出现以下错误:

{
  "author_name": [
    "This field is required."
  ]
}

但是当您将上述json提交给/book/update-partial/1/时,您将获得HTTP_STATUS_CODE = 200以及以下响应,

{
  "id": 1,
  "name": "PYTHON IN A NUT SHELL",
  "author_name": "Alex Martelli"
}

问题2)

serialized是一个将模型实例包装为可序列化对象的对象。并且您可以使用此序列化来生成带有serialized.data的简单JSON字符串。

问题3)

我认为,当您阅读上述答案后,您可以自己回答,并且您应该知道何时使用update以及何时使用partial_update

如果您还有任何疑问,请随时提出。我只是阅读了部分源代码的休息框架,对于某些术语可能还不太了解,请在出错时指出...

答案 1 :(得分:25)

部分更新 - PATCH http方法

完整更新 - PUT http方法

使用DRF进行更新时,您应该发送包含所有(必需)字段值的请求数据。当请求是通过PUT http方法时,至少就是这种情况。据我所知,您想要更新一个或至少不是所有模型实例字段。在这种情况下,使用PATCH http方法发出请求。 Django休息框架(DRF)将开箱即用。

示例(使用令牌身份验证):

curl -i -X PATCH -d '{"name":"my favorite banana"}' -H "Content-Type: application/json" -H 'Authorization: Token <some token>'  http://localhost:8000/bananas/

答案 2 :(得分:0)

我遇到一个问题,我的rest_framework序列化程序中的多属性/字段验证正在处理POST / resources /请求,但未通过PATCH / resources /请求进行工作。在PATCH情况下失败,因为它仅在提供的attrs字典中查找值,而没有退回到self.instance中的值。添加方法get_attr_or_default来进行后备工作似乎奏效了:

class EmailSerializer(serializers.ModelSerializer):

    def get_attr_or_default(self, attr, attrs, default=''):
        """Return the value of key ``attr`` in the dict ``attrs``; if that is
        not present, return the value of the attribute ``attr`` in
        ``self.instance``; otherwise return ``default``.
        """
        return attrs.get(attr, getattr(self.instance, attr, ''))

    def validate(self, attrs):
        """Ensure that either a) there is a body or b) there is a valid template
        reference and template context.
        """
        existing_body = self.get_attr_or_default('body', attrs).strip()
        if existing_body:
            return attrs
        template = self.get_attr_or_default('template', attrs)
        templatecontext = self.get_attr_or_default('templatecontext', attrs)
        if template and templatecontext:
            try:
                render_template(template.data, templatecontext)
                return attrs
            except TemplateRendererException as err:
                raise serializers.ValidationError(str(err))
        raise serializers.ValidationError(NO_BODY_OR_TEMPLATE_ERROR_MSG)

答案 3 :(得分:-1)

只需重写序列化程序的 init 方法,即可:

def __init__(self, *args, **kwargs):
    kwargs['partial'] = True
    super(DemoSerializer, self).__init__(*args, **kwargs)

答案 4 :(得分:-3)

您忘记了serializer.save()

您可以通过以下方式完成此操作。 。

class DemoViewSet(viewsets.ModelViewSet):
    serializer_class = DemoSerializer

    def partial_update(self, request, pk=None):
        serializer = DemoSerializer(request.user, data=request.data, partial=True)
        serializer.save()
        serializer.is_valid(raise_exception=True)
        return Response(serializer.data)

此外,您不需要覆盖序列化程序中的更新方法。