我是Django REST Framework的新手,并尝试用于我正在开发的新项目。所以基于官方教程,我正在尝试创建几个get / post / put请求,但是使用put请求我收到以下错误:
预期视图使用名为“pk”的URL关键字参数调用ExampleUpdateView。修复您的网址,或者在视图上正确设置
.lookup_field
属性。
models.py
class ExampleModel(models.Model):
foo_field = models.CharField(primary_key=True, max_length=15)
bar_field = models.CharField(max_length=30)
last_updated_by = models.CharField(max_length=15)
last_updated_on = models.DateTimeField()
class Meta:
managed = True
db_table = 'example_db'
unique_together = (('foo_field', 'bar_field'),)
serializers.py
class ExampleSerializer(serializers.ModelSerializer):
class Meta:
model = ExampleModel
fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
urls.py
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
views.py
class ExampleCreateView(generics.CreateAPIView):
serializer_class = ExampleSerializer
queryset = ExampleModel.objects.all()
class ExampleUpdateView(generics.UpdateAPIView):
queryset = ExampleModel.objects.all()
serializer_class = ExampleSerializer
我认为我可能遇到的问题是我有一个复合键。我尝试了其他通用视图(CreateAPIView&amp; ListAPIView),它们的工作非常好。我是否需要更新def_update
方法?我是否需要更改serializers.py
中的任何内容?
这是我从GET请求获得的现有JSON对象,并且正在尝试更新:
{
"foo_field": "john",
"bar_field": "doe",
"last_updated_by": "batman",
"last_updated_on": "2017-02-09"
}
我查看了以下重复项,但这些解决方案似乎都不适用于我:
Django Rest Framework: Unclear error message
答案 0 :(得分:2)
首先,我将重构您的代码并展示代码示例。之后我会解释这些变化。
models.py
class ExampleModel(models.Model):
foo_field = models.CharField(primary_key=True, max_length=15)
# rest ...
您已将foo_field
设为主键。使用字符串(VARCHAR
)作为主键是一种不好的做法。强烈建议使用surrogate keys。这将由Django自动完成。它添加了一个字段id
作为主键。
serializers.py
现在可以正常工作了。无需任何更改。此外views.py
应该无需更改即可运行。不过,我将foo_field
作为主键覆盖该选项。
<强> views.py
强>
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field`
您也可以将其删除,但在urls.py
中进行一些更改非常重要。
<强> urls.py
强>
url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
为了使Web服务具有ReSTful,他们必须遵守REST原则。最重要的规则之一是我们不应该在URL中使用动词来描述动作。另一个约定是资源名称以复数形式用于描述集合,标识符用于访问单个资源。
您的资源名为示例,因此我们使用示例作为集合名称。获取或更新等动词在URL中没有位置。 HTTP方法负责正确的操作。
如果您想使用foo_field
作为主键,则必须更改更新视图的网址:
url(r'^examples/(?P<pk>[\w-]+)/$',views.ExampleUpdateView.as_view()),
这是因为您的foo_field
是CharField
(或字符串),因此传递给它的参数应匹配任何字母数字字符(\w
)和连字符({{1} })。
如果您愿意,可以在网址正则表达式中使用-
作为命名组,而不是foo_field
。请注意您在视图中对其进行调整,为pk
和lookup_field
设置正确的值。
我再次强烈建议使用代理键并让Django完成此任务。
现在您可以了解为什么lookup_url_kwarg
和ListAPIView
有效了。他们不需要传递给网址的参数,并且被正确调用
您的CreateAPIView
无法正常工作,因为匹配的网址只接受数字且与您的主键UpdateAPIView
不匹配。
答案 1 :(得分:0)
与update()
一起使用UpdateAPIView
。
class ExampleUpdateView(generics.UpdateAPIView):
queryset = ExampleModel.objects.all()
serializer_class = ExampleSerializer
def update(self, request, *args, **kwargs):
instance = self.get_object()
instance.foo_field = request.data.get("foo_field")
instance.bar_field = request.data.get("bar_field")
instance.last_updated_by = request.data.get("last_updated_by")
instance.last_updated_on = request.data.get("last_updated_on")
instance.save()
serializer = self.get_serializer(instance)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)