Django REST框架补丁请求使用查询而不是ID或PK

Django REST框架补丁请求使用查询而不是ID或PK,django,django-rest-framework,Django,Django Rest Framework,我有一个建筑模型,我已经为它创建了序列化程序和ModelViewSet 我可以通过发送补丁请求并指定模型ID来更新模型,如下所示: curl http://127.0.0.1/dashboard/api/v1/buildings/3/ \ --request PATCH \ --header "Content-Type: application/json" \ --data '{"name": "School","address": "123 Some Street","description"

我有一个建筑模型,我已经为它创建了序列化程序和ModelViewSet

我可以通过发送补丁请求并指定模型ID来更新模型,如下所示:

curl http://127.0.0.1/dashboard/api/v1/buildings/3/ \
--request PATCH \
--header "Content-Type: application/json" \
--data '{"name": "School","address": "123 Some Street","description": "A place to learn"}'
如何通过查询字段而不是传递模型ID来更新建筑模型?例如:

curl http://127.0.0.1/dashboard/api/v1/buildings/?name=hospital \
--request PATCH \
--header "Content-Type: application/json" \
--data '{"name": "School","address": "123 Some Street","description": "A place to learn"}'
请注意,建筑名称是唯一的

此功能非常有用,因为客户机通常不知道模型ID,而是知道它希望更新的模型的属性


视图.py

class APIBuildingsViewSet(viewsets.ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'address']
class Building(models.Model):
    building_id = models.AutoField('ID', auto_created=True, primary_key=True)
    name        = models.CharField('Name', max_length=125, null=True, blank=False, unique=True)
    address     = models.CharField('Address', max_length=256, null=False, blank=False)
    user_id     = models.ForeignKey('accounts.User', on_delete=models.CASCADE, default=1)

    def __str__(self):
        return self.name
class BuildingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Building
        fields = ('building_id', 'name', 'address', 'user_id')
router = DefaultRouter()
router.register(r'buildings', views.APIBuildingsViewSet, base_name='buildings')

urlpatterns = [
    url(r'^api/', include(router.urls)),
]
型号.py

class APIBuildingsViewSet(viewsets.ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'address']
class Building(models.Model):
    building_id = models.AutoField('ID', auto_created=True, primary_key=True)
    name        = models.CharField('Name', max_length=125, null=True, blank=False, unique=True)
    address     = models.CharField('Address', max_length=256, null=False, blank=False)
    user_id     = models.ForeignKey('accounts.User', on_delete=models.CASCADE, default=1)

    def __str__(self):
        return self.name
class BuildingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Building
        fields = ('building_id', 'name', 'address', 'user_id')
router = DefaultRouter()
router.register(r'buildings', views.APIBuildingsViewSet, base_name='buildings')

urlpatterns = [
    url(r'^api/', include(router.urls)),
]
序列化程序.py

class APIBuildingsViewSet(viewsets.ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'address']
class Building(models.Model):
    building_id = models.AutoField('ID', auto_created=True, primary_key=True)
    name        = models.CharField('Name', max_length=125, null=True, blank=False, unique=True)
    address     = models.CharField('Address', max_length=256, null=False, blank=False)
    user_id     = models.ForeignKey('accounts.User', on_delete=models.CASCADE, default=1)

    def __str__(self):
        return self.name
class BuildingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Building
        fields = ('building_id', 'name', 'address', 'user_id')
router = DefaultRouter()
router.register(r'buildings', views.APIBuildingsViewSet, base_name='buildings')

urlpatterns = [
    url(r'^api/', include(router.urls)),
]
url.py

class APIBuildingsViewSet(viewsets.ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'address']
class Building(models.Model):
    building_id = models.AutoField('ID', auto_created=True, primary_key=True)
    name        = models.CharField('Name', max_length=125, null=True, blank=False, unique=True)
    address     = models.CharField('Address', max_length=256, null=False, blank=False)
    user_id     = models.ForeignKey('accounts.User', on_delete=models.CASCADE, default=1)

    def __str__(self):
        return self.name
class BuildingSerializer(serializers.ModelSerializer):
    class Meta:
        model = Building
        fields = ('building_id', 'name', 'address', 'user_id')
router = DefaultRouter()
router.register(r'buildings', views.APIBuildingsViewSet, base_name='buildings')

urlpatterns = [
    url(r'^api/', include(router.urls)),
]
您可以在
模型视图集中设置您的:

class APIBuildingsViewSet(viewsets.ModelViewSet):
    queryset = Building.objects.all()
    serializer_class = BuildingSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name', 'address']
    lookup_field = 'name'

然后,您可以使用建筑物名称访问详细路线:
/api/v1/buildings/hospital/

让客户先查找id有什么不对?然后他们可以决定如何处理多个建筑物同名的情况。这种方法没有错。我只是希望有一种方法可以让客户端用一个API请求而不是两个API请求来更新一栋建筑(第一个请求获得一栋建筑的pk,第二个请求更新该建筑)。我没有尝试过,但是你能将
lookup\u field
设置为非唯一字段吗?看起来很危险。@RishiG我只是尝试一下,不,您不能对非唯一字段使用此方法。在尝试检索对象时(如果有多个对象的字段值相同),此方法将中断。