我正在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()函数中的硬编码值。我发现了一些关于在视图中设置自定义上下文的小知识(在序列化程序中我可以访问然后访问它们的地方,但似乎对这个问题来说是一个过大的杀伤力,我认为这很普遍,并且应该应该有预制的解决方案)不见了。
答案 0 :(得分:0)
您将关联来自特定EduApp
的特定路由,或将其传递到有效负载中。
路由/eduapp/10/tasks
可用于创建特定的Task
,同时它具有有关eduapp_id
的信息,以帮助您查找要与之关联的唯一实例。 。
所以现在您可以查找:
instance.eduapp = EduApp.objects.get(id=eduapp_id)
假设您将参数命名为eduapp_id