2015-01-03 3 views
3

Я использую Django REST Framework для предоставления API для своего мобильного приложения. Мне нужно отправить дополнительный аргумент, когда я создаю новое устройство по электронной почте своего владельца.Получить идентификатор недавно созданного объекта Django Rest Framework

На самом деле я отправить JSON, похожее на это:

{"os_type": "AND", 
"token": "dfsdfdfsd", 
"email": "[email protected]" 
} 

Мне нужно передать некоторые данные в стандартном ModelViewSet и перекрывает небольшую часть (извлечь электронную почту владельца и связать его с устройством недавно созданного. проблема заключается в том, что я не знаю, как получить идентификатор этого нового объекта

у меня есть эта 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 

«Creat ed "- это тип Response, который будет отображаться со всей информацией, но я хотел бы получить идентификатор более элегантным или правильным способом.

И это моя модель устройства:

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) 

Как решить эту проблему?

+0

Вы просто пытаетесь сделать ассоциацию после создания объекта? (Только хэдз-ап, [это похоже на вопрос о стиле XY) (http://meta.stackoverflow.com/q/254341/359284)). Есть намного более простые способы сделать это на уровне представления или сериализатора, если это так. –

+0

@KevinBrown Да, я хочу связать объект Device с объектом Owner после создания устройства. Контекст: у меня есть мобильное приложение, но я не прошу зарегистрироваться. Я беру его письмо автоматически и создаю нового владельца. Затем я отправляю register_token на сервер с его электронной почтой и свяжусь с ним. Наконец, приложение позволяет отправлять голоса и получать уведомления, но я все это сделал. – antonio

+0

Во всяком случае, я думаю, что я решил исходную проблему, переопределив полную сохранность объекта сериализации, я не знал, что работает аналогично сохраненным формам. – antonio

ответ

9

Вы можете выполнять действия после того, как объекты создаются в Django REST Framework по overriding perform_create on your view.

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. Ошибка для неизвестного письма больше не включает уведомление об исключении, сообщение, которое там уже должно быть в порядке.

Кроме того, если есть способ, чтобы связать текущий пользователь делает запрос (при условии, в request.user) для владельца устройства создаются (owner в данном случае), вы можете пропустить их предоставление по электронной почте , Это зависит от того, как API должен функционировать, конечно, потому что вам может быть интересно разрешить пользователям связывать устройства с учетной записью другого владельца.

0

Наконец-то я решил проблему написания своего собственного кода, чтобы сохранить объект serializer и получить непосредственно идентификатор.

Это полный код:

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) 
Смежные вопросы