我对Django REST框架不是很熟悉,并且已经尝试了很多东西但是无法使我的PATCH请求工作。
我有一个模型序列化器。这与我用来添加新条目的条目相同,理想情况下我想在更新条目时重复使用。
class TimeSerializer(serializers.ModelSerializer):
class Meta:
model = TimeEntry
fields = ('id', 'project', 'amount', 'description', 'date')
def __init__(self, user, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
super(TimeSerializer, self).__init__(*args, **kwargs)
self.user = user
def validate_project(self, attrs, source):
"""
Check that the project is correct
"""
.....
def validate_amount(self, attrs, source):
"""
Check the amount in valid
"""
.....
我尝试使用基于类的视图:
class UserViewSet(generics.UpdateAPIView):
"""
API endpoint that allows timeentries to be edited.
"""
queryset = TimeEntry.objects.all()
serializer_class = TimeSerializer
我的网址是:
url(r'^api/edit/(?P<pk>\d+)/$', UserViewSet.as_view(), name='timeentry_api_edit'),
我的JS电话是:
var putData = { 'id': '51', 'description': "new desc" }
$.ajax({
url: '/en/hours/api/edit/' + id + '/',
type: "PATCH",
data: putData,
success: function(data, textStatus, jqXHR) {
// ....
}
}
在这种情况下,我希望我的描述能够更新,但是我得到了需要字段的错误(对于'project'和所有其他字段)。验证失败。如果添加到AJAX调用所有字段,它仍然无法检索“项目”。
我也尝试过自己的观点:
@api_view(['PATCH'])
@permission_classes([permissions.IsAuthenticated])
def edit_time(request):
if request.method == 'PATCH':
serializer = TimeSerializer(request.user, data=request.DATA, partial=True)
if serializer.is_valid():
time_entry = serializer.save()
return Response(status=status.HTTP_201_CREATED)
return Response(status=status.HTTP_400_BAD_REQUEST)
由于相同的原因(对于字段的验证失败),这对于部分更新不起作用,即使我已经发送了所有字段,它也不起作用。它创建一个新条目,而不是编辑现有条目。
我想重复使用相同的序列化程序和验证,但我愿意接受任何其他建议。 此外,如果有人有一段工作代码(ajax代码 - &gt; api view-&gt;序列化器)会很棒。
答案 0 :(得分:12)
class DetailView(APIView):
def get_object(self, pk):
return TestModel.objects.get(pk=pk)
def patch(self, request, pk):
testmodel = self.get_object(pk)
serializer = TestModelSerializer(testmodel, data=request.data, partial=True) # set partial=True to update a data partially
if serializer.is_valid():
serializer.save()
return JsonReponse(code=201, data=serializer.data)
return JsonResponse(code=400, data="wrong parameters")
Documentation
您无需编写partial_update
或覆盖update
方法。只需使用patch
方法。
答案 1 :(得分:7)
确保 http_method_names 中有“PATCH”。或者你可以这样写:
@property
def allowed_methods(self):
"""
Return the list of allowed HTTP methods, uppercased.
"""
self.http_method_names.append("patch")
return [method.upper() for method in self.http_method_names
if hasattr(self, method)]
如documentation中所述:
默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。您可以使用partial参数以允许部分更新。
在视图中覆盖update
方法:
def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = TimeSerializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save(customer_id=customer, **serializer.validated_data)
return Response(serializer.validated_data)
或者只是在视图中覆盖方法partial_update
:
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
序列化程序调用 ModelSerializer 的更新方法(请参阅sources):
def update(self, instance, validated_data):
raise_errors_on_nested_writes('update', self, validated_data)
# Simply set each attribute on the instance, and then save it.
# Note that unlike `.create()` we don't need to treat many-to-many
# relationships as being a special case. During updates we already
# have an instance pk for the relationships to be associated with.
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
更新将 validated_data 值推送到给定实例。请注意,更新不应假定所有字段都可用。这有助于处理部分更新( PATCH 请求)。
答案 2 :(得分:4)
我在DRF中使用patch
为viewset
方法工作。我改变你的代码:
class UserViewSet(viewsets.ModelViewSet):
queryset = TimeEntry.objects.all()
serializer_class = TimeSerializer
def perform_update(self, serializer):
user_instance = serializer.instance
request = self.request
serializer.save(**modified_attrs)
return Response(status=status.HTTP_200_OK)
答案 3 :(得分:0)
改为使用UpdateModelMixin
并覆盖class UserViewSet(viewsets.ModelViewSet):
queryset = TimeEntry.objects.all()
serializer_class = TimeSerializer
def perform_update(self, serializer):
serializer.save()
# you may also do additional things here
# e.g.: signal other components about this update
UpdateModelMixin
方法
update
就是这样。不要在此方法中返回任何内容。 _prefetched_objects_cache
已经实施了.background{
background-image: url('../assets/bg/chatbg1.jpg');
background-size: cover;
background-attachment: fixed; /*-- here should be fixed --*/
}
.messageLeft{
float: left;
display: inline;
padding: 4px 5px;
background-color: transparent;/*-- make background transparent--*/
margin: 5px;
color: black;
border-radius: 3px;
word-break: break-all;
//width: 250px;
}
.messageRight{
float: right;
display: inline;
padding: 4px 5px;
background-color: transparent; /*-- make background transparent--*/
margin: 5px;
color: black;
border-radius: 3px;
word-break: break-all;
//width: 250px;
方法,可以将更新的数据作为回复返回给您,并清除Story <-- 1 ----- N --> StoryLocation
。请参阅outer product。
答案 4 :(得分:0)
我也遇到了这个问题,我解决了它,重新定义了get_serializer_method并添加了自定义逻辑来处理部分更新。 Python 3
class ViewSet(viewsets.ModelViewSet):
def get_serializer_class(self):
if self.action == "partial_update":
return PartialUpdateSerializer
注意:您可能必须重写序列化程序上的partial_update函数。像这样:
class PartialUpdateSerializer(serializers.Serializer):
def partial_update(self, instance, validated_data):
*custom logic*
return super().update(instance, validated_data)
答案 5 :(得分:0)
另一种可能性是通过URL发出请求。例如,我有一个这样的模型
class Author(models.Model):
FirstName = models.CharField(max_length=70)
MiddleName = models.CharField(max_length=70)
LastName = models.CharField(max_length=70)
Gender = models.CharField(max_length=1, choices = GENDERS)
user = models.ForeignKey(User, default = 1, on_delete = models.CASCADE, related_name='author_user')
IsActive = models.BooleanField(default=True)
class Meta:
ordering = ['LastName']
还有这样的视图
class Author(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
因此可以输入http://127.0.0.1:8000/author/来吸引或发表作者。如果我要发出PATCH请求,则可以从您的客户端指向http://127.0.0.1:8000/author/ID_AUTHOR。例如在angular2中,您可以拥有类似的内容
patchRequest(item: any): Observable<Author> {
return this.http.patch('http://127.0.0.1:8000/author/1', item);
}
假设您已经配置了CORS,并且前后具有相同的模型。 希望它会有用。