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

2024-06-02 09:09:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Django REST框架的新手,我正在为一个新项目尝试它。因此,根据官方教程,我试图创建几个get/post/put请求,但是对于put请求,我得到了以下错误:

Expected view ExampleUpdateView to be called with a URL keyword argument named "pk". Fix your URL conf, or set the .lookup_field attribute on the view correctly.

这是我必须的文件:

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

我想我可能有一个问题,我有一个复合键。我尝试了其他通用视图(createapiew&ListAPIView),它们工作得非常好。我需要更新def_update方法吗?我需要在serializers.py中更改任何内容吗?

这是一个现有的JSON对象,我是从GET请求中获取的,并试图更新:

{
    "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?


Tags: djangopyviewfieldfooonmodelsbar
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中使用动词来描述操作。另一种约定是,资源名称以复数形式用于描述集合,而标识符用于访问单个资源。

您的资源称为示例,因此我们使用示例作为集合名。像get或update这样的动词在URL中没有位置。HTTP方法负责正确的操作。

如果要使用foo_field作为主键,则必须更改更新视图的url:

url(r'^examples/(?P<pk>[\w-]+)/$',views.ExampleUpdateView.as_view()),

这是因为您的foo_field是一个CharField(或字符串),所以传递给它的参数应该匹配任何字母数字字符(\w)和连字符(-)。
如果愿意,可以在url regex中使用foo_field作为命名组,而不是pk。注意,在视图中调整它,为lookup_fieldlookup_url_kwarg设置正确的值。

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

现在您可以理解ListAPIViewCreateAPIView工作的原因了。它们不需要传递到url的参数,并且被正确调用。
您的UpdateAPIView无法工作,因为匹配的url只接受数字,与您的主键foo_field不匹配。

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)

相关问题 更多 >