【问题标题】:post group name with the multiple device selected选择多个设备的帖子组名称
【发布时间】:2017-03-02 02:16:21
【问题描述】:

我正在尝试为设备组和设备创建 api。一个设备组可以有多个设备,我希望有多个设备的设备组的 post api,因为只有在选择设备时才会显示组创建,并且用户可能会选择多个设备然后创建一个新组。这样在创建组时,那些选定的设备也应该显示为 device_list

这是我的代码,我不确定如何发布请求

class BaseDevice(PolymorphicModel):
  name = models.CharField(max_length=250, blank=False, null=False)
  group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)

class Device(BaseDevice):
  description = models.TextField(blank=True, null=True)

class DeviceGroup(models.Model):
    name = models.CharField(max_length=250, blank=False, null=False)  

class DeviceIdSerializer(serializers.ModelSerializer):
    id = serializers.UUIDField(source='token', format='hex', read_only=True)
    class Meta:
        model = Device
        # id is the token of the device and name is the name of the device
        fields = ('id', 'name')

class DeviceGroupSerializer(serializers.ModelSerializer):
    name = serializers.StringRelatedField()
    device_list = DeviceIdSerializer(read_only=False, many=True, required=False, source="groups")
    class Meta:
        model = DeviceGroup
        # name is the name of group created and device_list is the list of devices with id(token) and device name
        fields = ('id', 'name', 'device_list')

    def create(self, validated_data):
        print ('validated_data', validated_data)
        device_list_data = validated_data.pop('device_list')
        group = DeviceGroup.objects.create(**validated_data)
        for device_list in device_list_data:
            BaseDevice.objects.create(group=group, **device_list)
        return group

class DeviceGroupAPIView(APIView):
    permission_classes = (permissions.IsAuthenticated,)

    def get_object(self, user, token):
        try:
            return BaseDevice.objects.filter(owner=user).get(token=token)
        except ObjectDoesNotExist:
            return error.RequestedResourceNotFound().as_response()


    def post(self, request, token=None, format=None):
        device_group_instance = DeviceGroup.objects.get(token=token)
        for device_token in request.data['devices']:
            device = Device.objects.get(token=device_token, owner=request.user)
            device.group = device_group_instance

这是我的 api 设计

{
   "data":[
      {
         "id":1,
         "name":"Home",
         "device_list":[
            {
               "id":"481cfef5a4884e52a63d135967fbc367",
               "name":"Oxygen Provider"
            },
            {
               "id":"7eb006d6db50479aa47f887da0d4f10e",
               "name":"Fan Speed"
            }
         ]
      },
      {
         "id":2,
         "name":"Business",
         "device_list":[

         ]
      }
   ]
}

更新

url(r'^device_group/(?P<token>[0-9a-f]+)/add$', DeviceGroupAPIView.as_view(), name='device_group'),

【问题讨论】:

  • 它是否正确创建了组和设备?是否抛出任何错误?您传递的实例应该是 DeviceGroup 或 None,而不是 Device
  • 对不起,我无法测试它,因为表单没有显示在可浏览的 api 中。
  • 我现在得到了表单,但是显示了表单的媒体类型和内容类型。 DeviceGroup 的实例?我不明白
  • 需要指出的几件事:您的设备依赖于存在的组。您不能先创建设备,然后再创建组。您可以遵循 django 管理方法并允许在添加设备时添加新组或更改您的模型以允许首先创建设备。 DRF 也有视图集,可能会让你更容易。我不明白为什么添加组需要令牌。我会尝试为您编写一些代码,但您应该阅读更多关于 DRF 以及如何编写适当的 API 的内容
  • token 是我的设备的 ID,需要在该设备中发布组。

标签: python django django-rest-framework


【解决方案1】:

我稍微修改了你的代码

class BaseDevice(PolymorphicModel):
    name = models.CharField(max_length=250, blank=False, null=False)
    group = models.ForeignKey('DeviceGroup', related_name="groups", null=True, blank=True)

class Device(BaseDevice):
    description = models.TextField(blank=True, null=True)

class DeviceGroup(models.Model):
    name = models.CharField(max_length=250, blank=False, null=False)

class DeviceIdSerializer(serializers.ModelSerializer):
    id = serializers.UUIDField(source='token', format='hex', read_only=True)
    # token does not exist in your model so this will not be included
    class Meta:
        model = Device
        # id is the token of the device and name is the name of the device
        fields = ('id', 'name')

class DeviceGroupSerializer(serializers.ModelSerializer):
    device_list = DeviceIdSerializer(read_only=False, many=True, required=False, source="groups")
    class Meta:
        model = DeviceGroup
        # name is the name of group created and device_list is the list of devices with id(token) and device name
        fields = ('id', 'name', 'device_list')

    def create(self, validated_data):
        print ('validated_data', validated_data)
        device_list_data = validated_data.pop('groups', [])
        # notice that I pop 'groups' because validation changes the input data 
        # to match the field names
        # Also since it is not required I've added a default value
        group = DeviceGroup.objects.create(**validated_data)
        devices = [BaseDevice(group=group, **device_list) for device_list in device_list_data] 
        BaseDevice.objects.bulk_create(devices)
        # Use bulk create when you have to create multiple objects
        # It hits the db only once instead of multiple times
        return group

class DeviceGroupAPIView(ModelViewSet):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = DeviceGroupSerializer
    queryset = DeviceGroup.objects.all()
    # Although I have used ModelViewSet, you could use any other one
    # I used this so that I don't need to write the code for create,
    # update, delete or list


# urls.py
router = routers.DefaultRouter()
router.register(r'device_group', DeviceGroupAPIView, base_name='device_group')
# this gives the following urls
# /device_group/ POST to create, GET to list    
# /device_group/(?<pk>\d+)/  GET to retrieve single DeviceGroup, PATCH/PUT to update it, and DELETE to delete it

这是用于 POST 的 JSON 结构,用于创建带有一堆设备的新 DeviceGroup

{
   "name":"Group Name",
   "device_list":[
      {
         "name":"Device 1"
      },
      {
         "name":"Device 2"
      },
      {
         "name":"Device 3"
      }
   ]
}

希望对你有帮助

另外你应该阅读更多关于Django-Rest-Framework

【讨论】:

  • 感谢您的解决方案。我有最后一个问题。您告诉将设备组的实例发送到 DeviceGroupSerializer 所以我更改了我的发布功能。那是你说的吗?作为初学者,我不想使用 ModelViewSet,所以我尝试使用 APIView。你能看看我的帖子功能吗?
  • 您的 DeviceGroup 没有名为 token 的字段,因此您不能使用它来执行查找。但是,如果您有 DeviceGroup 对象,那么您分配的方式就足够了(使用.save())。如果这是您的第一个 Django 项目,您可能希望先搁置它并尝试一些教程
  • 我在 DeviceGroup 中的 token 字段为 token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)。
  • 如果我的帖子是正确的,你能用我的帖子功能更新你的答案吗?我会将其标记为已回答并感谢您的建议。我对英语的理解很差,这让我很难掌握这个概念
  • 我的答案不需要post() 方法,因为基类中的方法就足够了,而序列化程序create() 可以完成所需的一切。另一方面,您的 post() 根本不使用序列化程序。它需要 url 中的组令牌和数据中的设备令牌(我在 url 中没有任何内容)。所以这两个代码应该独立工作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多