我有以下两个模型:Blueprint和Workload。 Blueprint模型实例应该具有与之关联的Workload集合。 最初,应该允许独立创建Blueprint和Workload实例。 一个完整的典型场景如下:
1)创建一个新的Blueprint实例
2)创建一个新的Workload实例
3)创建的Workload实例被添加到Blueprint的“工作负载”集合
python REPL版本是这样的:
blueprint = Blueprint(name="bluepint 1")
blueprint.save()
workload = Workload)name="workload 1")
workload.save()
blueprint.workloads.add(blueprint)
blueprint.save()
在我的python客户端中,我可以独立创建Blueprint和Workload的实例,而且没有问题。
我的问题是:将正确的HTTP方法和相应的URL语法添加到Blueprint的“工作负载”集合中是什么。
这是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
答案 0 :(得分:0)
我不是REST专家,但就REST而言,我相信你的网址应该是这样的:
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
上下文中的复制可能会像:
#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
}
为了制作这样的网址结构,您应该结帐drf-extensions或drf-nested-routers
另一种方法是将自定义detail
端点添加到/api/blueprint/
,例如:
http POST /api/blueprint/1/add_workload/ name="workload 2"
如果你使用Viewsets,这将会像这样:
#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)