获取最近创建的Django Rest Framework对象的id

时间:2015-01-03 22:13:35

标签: python django django-rest-framework

我正在使用Django REST Framework为我的移动应用程序提供API。当我创建一个新设备时,我需要发送作为额外参数的所有者的电子邮件。

实际上我发送了一个类似于此的json:

{"os_type": "AND",
 "token": "dfsdfdfsd",
 "email": "sdfdfd@sdfs.com"
}

我需要将一些数据传递给标准ModelViewSet并覆盖一小部分(提取所有者的电子邮件并将其与最近创建的设备关联。问题是我不知道如何获取这个新的id对象

我的Device模型有这个ModelViewSet:

class DeviceViewSet(viewsets.ModelViewSet):

    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def create(self, request):
        """
            Overrides the create method in order to get
            extra params: the email of the device's owner.
            When this is done, we pass the method to his parent.
        """
        print "creating..."

        created = super(DeviceViewSet, self).create(request)
        print type(created).__name__
        #[method for method in dir(created) if callable(getattr(created, method))]
        return created

“created”对象是Response类型,它将使用所有de信息进行渲染,但我希望以更优雅或正确的方式获取ID。

这是我的设备型号:

class Device(models.Model):
    """
    iOS or Android device, where is installed the app
    """

    ANDROID = 'AND'
    IOS = 'IOS'

    OS_DEVICES_CHOICES = (
        (ANDROID, 'Android'),
        (IOS, 'iOS'),
    )

    os_type = models.CharField(max_length=3, choices=OS_DEVICES_CHOICES)
    token = models.CharField(max_length=1000)

    active = models.BooleanField(default=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

我更喜欢不在我的设备模型中添加字段所有者,因为我已经拥有引用设备的所有者模型:

class Owner(models.Model):
    name = models.CharField(max_length=200, blank=True, null=True)
    biography = models.TextField(max_length=1000, blank=True, null=True)
    birthday = models.DateField(blank=True, null=True)
    country = models.CharField(max_length=50, blank=True, null=True)
    language = models.CharField(max_length=50, blank=True, null=True)

    email = models.EmailField(blank=True, null=True)

    devices = models.ManyToManyField(Device)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return u'[{0}] {1}'.format(self.id, self.name)

    def __unicode__(self):
        return u'[{0}] {1}'.format(self.id, self.name)

如何解决此问题?

2 个答案:

答案 0 :(得分:12)

您可以在overriding perform_create on your view之后在Django REST Framework中创建对象后执行操作。

class DeviceViewSet(viewsets.ModelViewSet):
    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def perform_create(self, serializer):
        from rest_framework.exceptions import ValidationError

        data = self.request.data

        if "email" not in data:
            raise ValidationError({
                "email": "No owner email provided",
            })

        try:
            owner = Owner.objects.get(email=data["email"])
        except Owner.DoesNotExist:
            return Response(
                'No owner with the email ({0}) found'.format(email),
                status=status.HTTP_406_NOT_ACCEPTABLE
            )

        device = serializer.save()

        owner.devices.add(device)

通过在视图上覆盖perform_create而不是create方法,您不必担心在升级期间您将丢失的create方法所做的任何更改。 perform_create方法是推荐的钩子,所以你不必担心这种方法。

我还对在设备创建之前完成的检查做了一些更改。

    如果电子邮件未与请求一起传递,则
  1. A ValidationError is being raised会出现400错误。这将产生与其他字段相同的样式错误消息,并应由默认异常处理程序处理。
  2. 如果用户提供的无效电子邮件与数据库中的所有者不匹配,则try...except仅限于DoesNotExist错误。这样可以防止您压扁未考虑的边缘情况,though the DoesNotExist and MultipleObjectsReturned exceptions是您应该从get电话中真正收到的唯一情况。
  3. 未知电子邮件的错误不再包含异常通知,已存在的消息应该没有问题。
  4. 此外,如果有办法将当前用户与请求(在request.user中提供)绑定到正在创建的设备的所有者(在这种情况下为owner),您可能希望跳过他们提供电子邮件。这取决于API当然应该如何运作,因为您可能有兴趣允许用户将设备绑定到另一个所有者的帐户。

答案 1 :(得分:0)

最后,我解决了编写自己的代码以保存序列化程序对象并直接获取ID的问题。

这是完整的代码:

class DeviceViewSet(viewsets.ModelViewSet):

    queryset = Device.objects.all()
    serializer_class = DeviceSerializer

    def create(self, request):
        """
            Overrides the create method in order to get
            extra params: the email of the device's owner.
            When this is done, we pass the method to his parent.
        """
        print "creating..."
        data = request.data
        email = None
        if 'email' in data:
            email = data['email']
        else:
            return Response("No owner email provided", status=status.HTTP_400_BAD_REQUEST)

        try:
            owner = Owner.objects.get(email=email)
        except Exception as e:
            print e
            return Response('No owner with the email ({0}) found, error: {1}'.format(email, e), 
                status=status.HTTP_406_NOT_ACCEPTABLE)


        serializer = DeviceSerializer(data=request.data)
        if serializer.is_valid():
            device = serializer.save()
            print device.id
            owner.devices.add(device)
            #device.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)