【问题标题】:DRF - Nested Routers - Create/Update nested object on POST/PUT/PATCHDRF - 嵌套路由器 - 在 POST/PUT/PATCH 上创建/更新嵌套对象
【发布时间】:2018-12-23 16:48:41
【问题描述】:

我目前正在启动一个简单的任务应用程序,我正在使用 Django 2.0.7、DRF 3.8.2 和 drf-nested-routes 0.90.2

我有这些模型:

class Client(TimeStampedModel):
    """
    This model describes a client for the railroader. It can be created by the manager in the back office
    We have at least one internal Client, which is Seelk, for internal projects
    """
    name = models.CharField(max_length=255, unique=True)
    description = models.TextField(null=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return "{} : {}".format(self.name, self.description)

class Project(TimeStampedModel):
    """
    This model represents a project for a client, which we are gonna track actions on
    """
    client = models.ForeignKey(
        'railroader.Client', on_delete=models.PROTECT, related_name='projects')
    name = models.CharField(max_length=255, unique=True)
    description = models.TextField(null=True)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return "{} for client {}".format(self.name, self.client.name)

所以,按照 drf-nested-routers 的文档,我这样设置我的序列化器:

class ClientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Client
        fields = ("id", "name", "description", "is_active", "projects")


class ProjectSerializer(serializers.ModelSerializer):
    class Meta:
        model = Project
        fields = ("id", "name", "description", "is_active")

我的观点是这样的:

class ClientViewset(viewsets.ModelViewSet):
    serializer_class = ClientSerializer
    permission_classes = (permissions.IsAuthenticated, AccountPermission)

    def get_queryset(self):
        queryset = Client.objects.all()
        is_active = self.request.query_params.get("is_active")
        if is_active:
            queryset = queryset.filter(is_active=is_active)
        return queryset


class ProjectViewset(viewsets.ModelViewSet):
    serializer_class = ProjectSerializer
    permission_classes = (permissions.IsAuthenticated, AccountPermission)

    def get_queryset(self):
        queryset = Project.objects.filter(client=self.kwargs["client_pk"])
        is_active = self.request.query_params.get("is_active")
        if is_active:
            queryset = queryset.filter(is_active=is_active)
        return queryset

最后,我的网址是这样的:

router = routers.SimpleRouter()
router.register(r"clients", viewsets.ClientViewset, base_name="clients")

projects_router = routers.NestedSimpleRouter(router, r"clients", lookup="client")
projects_router.register(r"projects", viewsets.ProjectViewset, base_name="projects")
urlpatterns = [
    re_path(r"^", include(router.urls)),
    re_path(r"^", include(projects_router.urls))
]

通过此设置,我可以拥有所需的嵌套路由,但如果我在嵌套路由上发布,我无法使用我的路由来创建新对象。

我在 github 上看到了一个 issue 谈论它,但是就像 2 年前一样,我想知道是否有人知道该怎么做。

提前致谢。

【问题讨论】:

  • 当您进行 POST 时,响应是什么?有什么错误吗?
  • 你也可以在这里发布你的序列化程序
  • @EnthusiastMartin 我没有问题,只是响应是我的对象,但 ID 为空,因为我忘记了 create。现在修好了,谢谢!

标签: python django django-rest-framework nested-routes drf-nested-routers


【解决方案1】:

发现我只是忘记了在序列化程序的 DRF 创建方法中返回一个实例不会在基础中创建对象。最后我有这个序列化程序:

class ProjectSerializer(serializers.ModelSerializer):
    def create(self, validated_data):
        client = Client.objects.get(pk=self.context["view"].kwargs["client_pk"])
        validated_data["client"] = client
        return Project.objects.create(**validated_data)

    class Meta:
        model = Project
        fields = ("id", "name", "description", "is_active")

【讨论】:

  • 顺便说一句,如果您将 'client' 添加到 Meta.fields 元组,它应该可以工作。在这种情况下,您不需要在 create 中设置它,它应该会自动为您处理。
  • @EnthusiastMartin 我做到了,但是序列化程序随后在验证中要求它,我不想手动发布客户端的 ID,因为我已经在他的嵌套网址中,它应该是自动的。仅在序列化程序中添加字段不适用于创建而不发送它。不过感谢您的帮助!
  • 啊,好的。我以为你在发布它。我的错。在这种情况下,也许在您的视图中覆盖 perform_create 并将客户端 ID 输入到序列化程序的保存方法中也是需要考虑的解决方案。
  • @EnthusiastMartin 嗯,这个很有趣,我也会测试一下。就良好实践而言,我认为两者都可以。我会让你知道你的实现。
猜你喜欢
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2020-10-03
  • 1970-01-01
相关资源
最近更新 更多