Python Django Rest Framework 部分更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41110742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Django Rest Framework partial update
提问by intelis
I'm trying to implement partial_update
with Django Rest Frameworkbut I need some clarification because I'm stuck.
我正在尝试partial_update
使用Django Rest Framework来实现,但我需要一些说明,因为我被卡住了。
Why do we need to specify partial=True?
In my understanding, we could easily update Demo object inside ofpartial_update
method. What is the purpose of this?What is inside of serialized variable?
What is inside ofserialized
variable inpartial_update
method? Is that a Demo object? What function is called behind the scenes?- How would one finish the implementation here?
为什么我们需要指定partial=True?
根据我的理解,我们可以轻松地更新partial_update
方法内部的 Demo 对象。这样做的目的是什么?序列化变量的内部是什么?方法
中serialized
变量的内部是什么partial_update
?那是 Demo 对象吗?后台调用了什么函数?- 在这里如何完成实施?
Viewset
视图集
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)
Serializer
序列化器
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
回答by Enix
I have the same questions as yours before, but when I dig into the source code of rest_framework, I got the following findings, hope it would help:
我之前和你有同样的问题,但是当我深入研究 rest_framework 的源代码时,我得到了以下发现,希望它会有所帮助:
For question 1. Why do we need to specify partial=True?
对于问题 1. 为什么我们需要指定 partial=True?
This question is related to HTTP verbs.
这个问题与HTTP 动词有关。
PUT: The PUT method replaces all current representations of the target resource with the request payload.
PUT:PUT 方法用请求有效负载替换目标资源的所有当前表示。
PATCH: The PATCH method is used to apply partial modifications to a resource.
PATCH:PATCH 方法用于对资源应用部分修改。
Generally speaking, partial
is used to check whether the fields in the model is needed to do field validation when client submitting data to the view.
一般来说,partial
用于在客户端向视图提交数据时检查模型中的字段是否需要进行字段验证。
For example, we have a Book
model like this, pls note both of the name
and author_name
fields are mandatory(not null & not blank).
例如,我们有一个Book
这样的模型,请注意name
和author_name
字段都是必填的(非空和非空)。
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')
For some scenarios, We may only need to update part of the fields in the model, e.g., we only need to update name
field in the Book
. So for this case, client will only submit the name
field with new value to the view. The data submit from the client may look like this:
对于某些情况下,我们可能只需要在模型中,如字段更新的一部分,我们只需要更新name
字段中Book
。因此,对于这种情况,客户端只会将name
具有新值的字段提交给视图。客户端提交的数据可能如下所示:
{"pk": 1, name: "PYTHON IN A NUT SHELL"}
But you may have notice that our model definition does not allow author_name
to be blank. So we have to use partial_update
instead of update
. So the rest framework will not perform field validation checkfor the fields which is missing in the request data.
但是您可能已经注意到我们的模型定义不允许author_name
为空白。所以我们必须使用partial_update
而不是update
. 因此,其余框架不会对请求数据中缺少的字段执行字段验证检查。
For testing purpose, you can create two views for both update
and partial_update
, and you will get more understanding what I just said.
出于测试目的,您可以为update
和都创建两个视图partial_update
,您将更了解我刚才所说的内容。
Example:
例子:
views.py视图.pyfrom 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网址.pyurlpatterns = 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'),
)
Data to submit
提交资料
{"pk": 1, name: "PYTHON IN A NUT SHELL"}
When you submit the above json to the /book/update/1/
, you will got the following error with HTTP_STATUS_CODE=400:
当您将上述 json 提交到 时/book/update/1/
,您将收到 HTTP_STATUS_CODE=400 的以下错误:
{
"author_name": [
"This field is required."
]
}
But when you submit the above json to /book/update-partial/1/
, you will got HTTP_STATUS_CODE=200 with following response,
但是,当您将上述 json 提交到 时/book/update-partial/1/
,您将获得 HTTP_STATUS_CODE=200 和以下响应,
{
"id": 1,
"name": "PYTHON IN A NUT SHELL",
"author_name": "Alex Martelli"
}
For question 2. What is inside of serialized variable?
对于问题 2. 序列化变量的内部是什么?
serialized
is a object wrapping the model instance as a serialisable object. and you can use this serialized to generate a plain JSON string with serialized.data
.
serialized
是一个将模型实例包装为可序列化对象的对象。并且您可以使用此序列化来生成带有serialized.data
.
For question 3. How would one finish the implementation here?
对于问题 3。如何完成这里的实施?
I think you can answer yourself when you have read the answer above, and you should have known when to use update
and when to used partial_update
.
我想你看了上面的回答就可以自己回答了,应该知道什么时候用update
,什么时候用partial_update
。
If you still have any question, feel free to ask. I just read part of the source odes of rest framework, and may have not understand very deeply for some terms, and please point it out when it is wrong...
如果您仍有任何疑问,请随时提问。刚刚看了rest框架的部分源码,可能对某些术语理解的不是很深,有错误的还请大家指出...
回答by Gooshan
For partial update- PATCHhttp method
对于部分更新- PATCHhttp 方法
For full update- PUThttp method
对于完整更新- PUThttp 方法
When doing an update with DRF, you are supposed to send request data that includes values for all (required) fields. This is at least the case when the request is via the PUT http method. From what I understand, you want to update one or at least not all model instance fields. In this case make a request with the PATCH http method. Django rest framework (DRF) will take care of it out of the box.
使用 DRF 进行更新时,您应该发送包含所有(必填)字段值的请求数据。至少当请求是通过 PUT http 方法时是这样。据我了解,您想要更新一个或至少不是所有模型实例字段。在这种情况下,使用 PATCH http 方法发出请求。Django 休息框架 (DRF) 将开箱即用。
Example (with token auth):
示例(使用令牌身份验证):
curl -i -X PATCH -d '{"name":"my favorite banana"}' -H "Content-Type: application/json" -H 'Authorization: Token <some token>' http://localhost:8000/bananas/
回答by Sergio Morstabilini
Just a quick note as it seems that nobody has already pointed this out:
只是一个简短的说明,因为似乎没有人已经指出了这一点:
serialized = DemoSerializer(request.user, data=request.data, partial=True)
The first argument of DemoSerializer should be a Demo instance, not a user (at least if you use DRF 3.6.2 like me).
DemoSerializer 的第一个参数应该是一个 Demo 实例,而不是一个用户(至少如果你像我一样使用 DRF 3.6.2)。
I don't know what you are trying to do, but this is a working example:
我不知道你想做什么,但这是一个有效的例子:
def partial_update(self, request, *args, **kwargs):
response_with_updated_instance = super(DemoViewSet, self).partial_update(request, *args, **kwargs)
Demo.objects.my_func(request.user, self.get_object())
return response_with_updated_instance
I do the partial update and then I do other things calling my_func and passing the current user and the demo instance already updated.
我做部分更新,然后我做其他事情,调用 my_func 并传递当前用户和已经更新的演示实例。
Hope this helps.
希望这可以帮助。
回答by jrwdunham
I had an issue where my multi-attribute/field validation in a rest_framework serializer was working with a POST /resources/ request but failing with a PATCH /resources/ request. It failed in the PATCH case because it was only looking for values in the supplied attrs
dict and not falling back to values in self.instance
. Adding a method get_attr_or_default
to do that fallback seems to have worked:
我有一个问题,我在 rest_framework 序列化程序中的多属性/字段验证正在处理 POST /resources/ 请求,但因 PATCH /resources/ 请求而失败。它在 PATCH 案例中失败了,因为它只是在提供的attrs
dict 中查找值,而不是回退到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)
回答by Alihaydar Gubatov
Just override initmethod of your serializer like that:
只需像这样覆盖序列化程序的init方法:
def __init__(self, *args, **kwargs):
kwargs['partial'] = True
super(DemoSerializer, self).__init__(*args, **kwargs)
回答by Jam Risser
You forgot serializer.save()
你忘了 serializer.save()
You can finish it the following way . . .
您可以通过以下方式完成。. .
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)
Also, you shouldn't need to override the update method in the serializer.
此外,您不需要覆盖序列化程序中的更新方法。