如何基于发布请求的URL中的ID创建带有FK字段的Django模型?

时间:2019-04-15 20:34:00

标签: python django serialization django-rest-framework

我正在DjangoRESTFramework中创建一个简单的API。我有以下一种任务模型,该模型属于一个且只有一个教育应用程序(简称eduapp):

class Task(models.Model):

    id = models.AutoField(primary_key=True, blank=True)
    name = models.TextField()
    eduapp = models.ForeignKey(EduApp, on_delete=models.CASCADE, null=False)

和简单的序列化器:

class TaskSerializer(serializers.ModelSerializer):

    taskId = serializers.IntegerField(source='id', required=False)

    class Meta:
        model = Task
        fields = ('taskId', 'name')

要访问这些任务,我有一个视图,该视图显示具有给定eduapp id(eduapp是另一个模型)的所有任务的列表。 Eduapp id是从用于请求的URL中获取的,该URL具有以下URL模式:path('eduapps/<int:eduapp_id>/tasks/', views.TaskList.as_view()),,例如:

localhost:8000/eduapps/1/tasks/给出的视图eduapp ID为1:


class TaskList(generics.ListCreateAPIView):

    serializer_class = TaskSerializer

    def get_queryset(self):
        queryset = Task.objects.all()
        eduapp_id = self.kwargs.get('eduapp_id')
        queryset = queryset.filter(eduapp=eduapp_id)
        return queryset

这很好用。但是,现在我要保存新任务(以前直接注入到DB中),而不仅仅是列出现有任务。 我想知道如何将eduapp_id从视图传播到序列化器中,然后如何将其用作新eduapp字段(模型中已经存在)的外键,类似于:

class TaskSerializer(serializers.ModelSerializer):

    taskId = serializers.IntegerField(source='id', required=False)

    eduapp = ??? some magic ???

    class Meta:
        model = Task
        fields = ('taskId', 'name', 'eduapp')   # new field name here

到目前为止,我已经尝试在序列化程序中定义自己的create函数并在其中设置FK:

    def create(self, validated_data):
        instance = Task.objects.create(**validated_data)
        instance.eduapp = EduApp.objects.get(id=1)
        return instance

此处的eduapp硬编码ID为1。这似乎可以正常工作,但是这样做使得POST仍要求正文包含值eduapp。为了解决这个问题,我将其包含在序列化器中:


    eduapp = EduAppSerializer(read_only=True,
                                many=False,
                                allow_null=True)

我不很喜欢,因为虽然它使POST不再需要eduapp,但我无意在对GET进行反序列化时实际显示eduapp部分(尽管我可以接受)。 / p>

但是,我无法超越create()函数中的硬编码值。我发现了一些关于在视图中设置自定义上下文的小知识(在序列化程序中我可以访问然后访问它们的地方,但似乎对这个问题来说是一个过大的杀伤力,我认为这很普遍,并且应该应该有预制的解决方案)不见了。

1 个答案:

答案 0 :(得分:0)

您将关联来自特定EduApp的特定路由,或将其传递到有效负载中。

路由/eduapp/10/tasks可用于创建特定的Task,同时它具有有关eduapp_id的信息,以帮助您查找要与之关联的唯一实例。 。

所以现在您可以查找:

instance.eduapp = EduApp.objects.get(id=eduapp_id)

假设您将参数命名为eduapp_id