Python Django REST框架中的更新/放置请求

Python Django REST框架中的更新/放置请求,python,django,rest,django-models,django-rest-framework,Python,Django,Rest,Django Models,Django Rest Framework,我是Django REST框架的新手,正在为一个新项目尝试它。因此,根据官方教程,我尝试创建几个get/post/put请求,但是使用put请求,我得到以下错误: 应使用名为“pk”的URL关键字参数调用view ExampleUpdateView。修复URL配置,或在视图上正确设置.lookup\u字段属性 以下是我需要的文件: models.py class ExampleModel(models.Model): foo_field = models.CharField(primar

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

应使用名为“pk”的URL关键字参数调用view ExampleUpdateView。修复URL配置,或在视图上正确设置
.lookup\u字段
属性

以下是我需要的文件:
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'),)
class ExampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExampleModel
        fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
class ExampleCreateView(generics.CreateAPIView):
    serializer_class = ExampleSerializer
    queryset = ExampleModel.objects.all()

class ExampleUpdateView(generics.UpdateAPIView):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field` url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
序列化程序.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'),)
class ExampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExampleModel
        fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
class ExampleCreateView(generics.CreateAPIView):
    serializer_class = ExampleSerializer
    queryset = ExampleModel.objects.all()

class ExampleUpdateView(generics.UpdateAPIView):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field` url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
url.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'),)
class ExampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExampleModel
        fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
class ExampleCreateView(generics.CreateAPIView):
    serializer_class = ExampleSerializer
    queryset = ExampleModel.objects.all()

class ExampleUpdateView(generics.UpdateAPIView):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field` url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()), 我想我可能的问题是我有一个复合键。我尝试了其他通用视图(CreateAPIView和ListAPIView),它们工作得非常好。我是否需要更新
def_update
方法?我是否需要更改
serializers.py中的任何内容

这是我从GET请求中获得的一个现有JSON对象,正在尝试更新:

{
    "foo_field": "john",
    "bar_field": "doe",
    "last_updated_by": "batman",
    "last_updated_on": "2017-02-09"
}
我查看了以下副本,但这些解决方案似乎都不适合我:

使用
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)
使用
update()
和您的
updateaview

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)

首先,我将重构您的代码并给出代码示例。之后我会解释这些变化

models.py

class ExampleModel(models.Model):
    foo_field = models.CharField(primary_key=True, max_length=15)
    # rest ...
您也可以忽略这一点,但对
url.py
进行一些更改是很重要的

url.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'),)
class ExampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExampleModel
        fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
class ExampleCreateView(generics.CreateAPIView):
    serializer_class = ExampleSerializer
    queryset = ExampleModel.objects.all()

class ExampleUpdateView(generics.UpdateAPIView):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field` url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()), 这是因为您的
foo\u字段
是一个
CharField
(或字符串),因此传递给它的参数应该匹配任何字母数字字符(
\w
)和连字符(
-
)。
如果愿意,您可以在url正则表达式中使用
foo_字段
作为命名组,而不是
pk
。请注意,在您的视图中对其进行调整,为
lookup\u字段
lookup\u url\u kwarg
设置正确的值

我再次强烈建议使用代理键,让Django来完成这项任务

现在您可以理解为什么
ListAPIView
createapieview
起作用了。它们不需要传递到url的参数,并且被正确调用。

您的
updateAliview
无法工作,因为匹配的url只接受数字,并且与您的主键
foo\u字段不匹配

首先,我将重构您的代码并展示代码示例。之后我会解释这些变化

models.py

class ExampleModel(models.Model):
    foo_field = models.CharField(primary_key=True, max_length=15)
    # rest ...
您也可以忽略这一点,但对
url.py
进行一些更改是很重要的

url.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'),)
class ExampleSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExampleModel
        fields = ('foo_field', 'bar_field', 'last_updated_by', 'last_updated_on')
url(r'^get_example/$', views.ExampleCreateView.as_view()),
url(r'^update_example/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()),
class ExampleCreateView(generics.CreateAPIView):
    serializer_class = ExampleSerializer
    queryset = ExampleModel.objects.all()

class ExampleUpdateView(generics.UpdateAPIView):
    queryset = ExampleModel.objects.all()
    serializer_class = ExampleSerializer
class ExampleUpdateView(generics.UpdateAPIView): # rest ... lookup_field = `foo_field` url(r'^examples/$', views.ExampleCreateView.as_view()), url(r'^examples/(?P<pk>\d+)/$',views.ExampleUpdateView.as_view()), 这是因为您的
foo\u字段
是一个
CharField
(或字符串),因此传递给它的参数应该匹配任何字母数字字符(
\w
)和连字符(
-
)。
如果愿意,您可以在url正则表达式中使用
foo_字段
作为命名组,而不是
pk
。请注意,在您的视图中对其进行调整,为
lookup\u字段
lookup\u url\u kwarg
设置正确的值

我再次强烈建议使用代理键,让Django来完成这项任务

现在您可以理解为什么
ListAPIView
createapieview
起作用了。它们不需要传递到url的参数,并且被正确调用。

您的
updateAliview
无法工作,因为匹配的url只接受数字,并且与您的主键
foo\u字段不匹配

您的
url.py
是一个明显的反模式。那不是休息!你没有把动词放进URL!HTTP请求方法应该映射到CRUD:POST-CREATE;获取-检索;放置-更新;DELETE-DELETE。您已将
foo_字段
设置为主键,因此不使用复合键。Django不支持复合键。您拥有的是
unique\u合在一起
,这是
unique键
,而不是复合键。顺便问一下,使用字符串作为主键是一种不好的做法。您需要使用
createapieview
updateapiew
的真正原因是什么?为什么不
ListCreateAPIView
RetrieveUpdatedStroyaPiView
?或者为什么不直接转到视图集?您的特殊要求是什么?CreateAPIView和UpdatePapiView只是示例。我尝试使用RetrieveUpdatedStroyapiView,但后者中的put请求仍然会给我相同的错误Your
URL.py
是一个明显的反模式。那不是休息!你没有把动词放进URL!HTTP请求方法应该映射到CRUD:POST-CREATE;获取-检索;放置-更新;DELETE-DELETE。您已将
foo_字段
设置为主键,因此不使用复合键。Django不支持复合键。您拥有的是
unique\u合在一起
,这是
unique键
,而不是复合键。顺便问一下,使用字符串作为主键是一种不好的做法。您需要使用
createapieview
updateapiew
的真正原因是什么?为什么不
ListCreateAPIView
RetrieveUpdatedStroyaPiView
?或者为什么不直接转到视图集?您的特殊要求是什么?CreateAPIView和UpdatePapiView只是示例。我尝试了RetrieveUpdatedStroyapiView,但是后者中的put请求仍然会给我相同的错误。非常感谢您提供了详细的答案。我现在明白了为什么ListApiew和ListApiew可以工作,而UpdateApiew不能。不幸的是,尽管我很想使用代理键(在本例中是Django的Autofield),但我无法选择它(我的技术负责人说了一个硬不)。我无法控制数据库(现在使用inspectdb)。我必须使用复合键,在VARCHAR中也是如此。@VasuGaur在这种情况下使用