Django 如何正确地将子对象添加到父对象';使用rest框架的s集合

Django 如何正确地将子对象添加到父对象';使用rest框架的s集合,django,django-rest-framework,Django,Django Rest Framework,我有以下两个模型:蓝图和工作负载。 Blueprint模型实例应具有与其关联的工作负载集合。 最初,应该允许单独创建蓝图和工作负载实例。 一个完整的典型场景如下: 1) 将创建一个新的Blueprint实例 2) 将创建一个新的工作负载实例 3) 创建的工作负载实例将添加到蓝图的“工作负载”集合中 python REPL版本如下所示: blueprint = Blueprint(name="bluepint 1") blueprint.save() workload = Workload)nam

我有以下两个模型:蓝图和工作负载。 Blueprint模型实例应具有与其关联的工作负载集合。 最初,应该允许单独创建蓝图和工作负载实例。 一个完整的典型场景如下:

1) 将创建一个新的Blueprint实例

2) 将创建一个新的工作负载实例

3) 创建的工作负载实例将添加到蓝图的“工作负载”集合中

python REPL版本如下所示:

blueprint = Blueprint(name="bluepint 1")
blueprint.save()
workload = Workload)name="workload 1")
workload.save()
blueprint.workloads.add(blueprint)
blueprint.save()
在我的python客户机中,我能够独立地创建蓝图和工作负载的实例,并且没有问题

我的问题是:向Blueprint的“workloads”集合添加工作负载的正确HTTP方法和相应的URL语法是什么

以下是models.py:

class Workload(models.Model):
    name = models.CharField(max_length=120, blank=True, default='')
    description = models.TextField()
    image = models.CharField(max_length=120, blank=True, default='')
    flavor = models.CharField(max_length=120, blank=True, default='')
    blueprint = models.ForeignKey('Blueprint', related_name='workloads', null=True)

    class Meta:
        ordering = ('name',)
        unique_together = ('blueprint', 'name')

    def __unicode__(self):
        return '%d: %s' % (self.name, self.description)


class Blueprint(models.Model):
    name = models.CharField(max_length=120, blank=True, default='')
    description = models.TextField()

    class Meta:
        ordering = ('name',)
下面是serializers.py:

# region Workload Serializer
class WorkloadSerializer(serializers.Serializer):
    pk = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=False, allow_blank=True, max_length=120)
    description = serializers.CharField(style={'type': 'textarea'})
    image = serializers.CharField(required=False, allow_blank=True, max_length=120)
    flavor = serializers.CharField(required=False, allow_blank=True, max_length=120)


    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Workload.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.name = validated_data.get('name', instance.name)
        instance.description = validated_data.get('description', instance.description)
        instance.image = validated_data.get('image', instance.image)
        instance.flavor = validated_data.get('flavor', instance.flavor)
        instance.save()
        return instance
# endregion


# region Blueprint Serializer
class BlueprintSerializer(serializers.ModelSerializer):
    workloads = serializers.StringRelatedField(many=True, required=False)
    pk = serializers.IntegerField(read_only=True)
    name = serializers.CharField(required=False, allow_blank=True, max_length=120)
    description = serializers.CharField(style={'type': 'textarea'})

    def create(self, validated_data):
        """
        Create and return a new `Snippet` instance, given the validated data.
        """
        return Blueprint.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        """
        instance.name = validated_data.get('name', instance.name)
        instance.description = validated_data.get('description', instance.description)
        instance.save()
        return instance

    class Meta:
        model = Blueprint
        fields = ('name', 'description', 'workloads')
# endregion

-Eugene

我不是REST专家,但就REST而言,我相信您的URL应该是这样的:

GET  /api/blueprint/                #list the blueprints
POST /api/blueprint/                #add new blueprint
GET  /api/blueprint/1/              #detail information about blueprint with id=1
PUT  /api/blueprint/1/              #update blueprint with id=1
GET  /api/blueprint/1/workloads/    #list all workloads of blueprint with id 1
POST /api/blueprint/1/workloads/    #add new workload to blueprint with id 1 workloads
GET  /api/blueprint/1/workloads/1   #detail information about workload with id=1 and blueprint id = 1
PUT  /api/blueprint/1/workloads/1   #update information about workload with id=1 and blueprint id = 1
因此,您在
REST
contex中的repl-exmaple将如下所示:

#request
http POST /api/blueprint/ name="bluepint 1"

#response
{
    "id": 1,
    "name": "bluepint 1",
    "description": ""
}

#request
http POST /api/blueprint/1/workloads/ name="workload 1"

#response
{
    "id": 1,
    "name": "workload 1",
    "description": "",
    "image": "",
    "flavor": "",
    "blueprint": 1
}
为了创建这样的url结构,您应该签出或

另一种方法是向
/api/blueprint/
添加自定义
细节
端点,类似于:

http POST /api/blueprint/1/add_workload/ name="workload 2"
如果使用视图集,这将如下所示:

#inside BlueprintViewset
@detail_route(methods=['post'])
def add_workload(self, request, pk):
    serializer = WorkloadSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save(blueprint=pk)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

谢谢!今晚我要试试这个