在Django REST Framework中更新/放置请求

时间:2018-02-13 23:44:54

标签: python django rest django-models django-rest-framework

我是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

Django REST Updateview with PUT POST

How do I use an UpdateView to update a Django Model?

2 个答案:

答案 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_fieldCharField(或字符串),因此传递给它的参数应匹配任何字母数字字符(\w)和连字符({{1} })。
如果您愿意,可以在网址正则表达式中使用-作为命名组,而不是foo_field。请注意您在视图中对其进行调整,为pklookup_field设置正确的值。

我再次强烈建议使用代理键并让Django完成此任务。

现在您可以了解为什么lookup_url_kwargListAPIView有效了。他们不需要传递给网址的参数,并且被正确调用 您的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)