2015-03-27 4 views
11

Я делаю обновление до DRF3.1.1 с 2.4. Я использовал собственный сериализатор для создания экземпляра объекта, который не является моделью.Django Rest Framework 3 Сериализаторы на немодельных объектах?

В 2.4 это было достаточно легко сделать, потому что в сериализаторе я бы создал объект в restore_object(). В представлении я бы вызвал serializer.is_valid(), а затем вытащил экземпляр объекта из сериализатора с помощью serializer.object. Тогда я мог делать все, что захочу.

С изменениями 3.x сложнее получить экземпляр из объекта, поскольку методы создания и обновления должны выполнять сохранение, а «serializer.object» больше не доступен.

В качестве примера я использовал это для своего объекта «UserRegistration». Это не модель, потому что это удобный объект, который сервер анализирует и хранит данные в ряде других объектов/таблиц db.

class UserRegistration(object): 
    def __init__(self, full_name, stage_name, password="", email="", locale="en_US"): 
     self.full_name = full_name 
     self.password = password 
     self.locale = locale 
     self.email = email 
     self.stage_name = stage_name 

Вот ассоциированная DRF-2,4 сериализатору:

class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def restore_object(self, attrs, instance=None): 
     if instance is not None: 
      instance.full_name = attrs.get('full_name', instance.full_name) 
      instance.password = attrs.get('password', instance.password) 
      instance.locale = attrs.get('locale', instance.locale) 
      instance.email = attrs.get('email', instance.email) 
      instance.stage_name = attrs.get('stage_name', instance.stage_name) 
      return instance 
     return UserRegistration(**attrs) 

Тогда на мой взгляд, я что-то вроде этого:

class UserRegistration(APIView): 
    throttle_classes =() 
    serializer_class = UserRegistrationSerializer 

    def post(self, request, format=None): 
     event_type = "user_registration" 
     serializer = UserRegistrationSerializer(data=request.DATA, context={'request': request}) 
     try: 
      if serializer.is_valid(): 
      user_registration = serializer.object 
      # save user_registration pieces in various places... 

Однако в DRF3, я serializer.object ушел. Документы говорят, что делать «валидацию» с помощью serializer.validated_data, но это всего лишь хэш, а не реальный объект. Есть ли способ получить объект?

Все это кажется более состоящим в браке с объектами БД, что в данном конкретном случае именно то, чего я пытаюсь избежать.

Я просто пропустил новую концепцию DRF3?

ответ

1

Да, вы можете получить сам объект, используя ФПИ 3. Вашего метод update должен иметь эту подпись update(self, instance, validated_data)

Вашего сериалайзера должны выглядеть следующим образом:

class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def update(self, instance, validated_data): 
      // here instance is the object . 
11

Благодаря @levi для наметившихся ответ, но, к сожалению, это еще не все, поэтому я думаю, что это более полный ответ.

Первоначально я спросил:

я просто не хватает какой-то новой концепции DRF3?

Оказывается ... Да. Я был. Документы говорят о новом Single-step object creation, что заставило меня подумать, что сериализация и модель стали более тесно связанными. Эта мысль была неправильной, потому что, если вы пишете собственный пользовательский сериализатор, вам придется делать фактическое сохранение объекта (или не) в новых методах и serializer.create().

Я также спросил:

В 2.4, это было достаточно легко сделать это, потому что в сериализаторе, я хотел бы создать объект в restore_object().В представлении я бы назвал serializer.is_valid(), а затем вытащил экземпляр объекта из сериализатора с помощью serializer.object. Тогда я мог делать все, что захочу.

С изменениями 3.x сложнее получить экземпляр из объекта, поскольку методы создания и обновления должны выполнять сохранение, а «serializer.object» больше не доступен.

Хотя нет serializer.object, которые вы можете использовать, чтобы созданный объект из после вызова serializer.is_valid(), метод serializer.save() возвращает сам объект, который в моем случае было просто отлично.

Итак, получается, что смена кода была не очень большой. Вот мой новый код, который очень доволен DRF-3:

class UserRegistration(object): 
    def __init__(self, full_name, stage_name, password="", email="", locale="en_US", notification_pref="ask"): 
     self.full_name = full_name 
     self.password = password 
     self.locale = locale 
     self.email = email 
     self.stage_name = stage_name 


class UserRegistrationSerializer(serializers.Serializer): 
    full_name = serializers.CharField(max_length=128, required=False) 
    stage_name = serializers.CharField(max_length=128) 
    password = serializers.CharField(max_length=128, required=False) 
    locale = serializers.CharField(max_length=10, required=False) 
    # use CharField instead of EmailField for email. We do our own validation later to make for a better error msg. 
    email = serializers.CharField(max_length=254, required=False) 

    def update(self, instance, validated_data): 
     instance.full_name = validated_data.get('full_name', instance.full_name) 
     instance.password = validated_data.get('password', instance.password) 
     instance.locale = validated_data.get('locale', instance.locale) 
     instance.email = validated_data.get('email', instance.email) 
     instance.stage_name = validated_data.get('stage_name', instance.stage_name) 
     return instance 

    def create(self, validated_data): 
     return UserRegistration(**validated_data) 

обратите внимание, что нет сохранения объекта к любой БД в Serializer. Я просто создаю или обновляю объект, а затем возвращаю его.

Теперь вид выглядит следующим образом:

class UserRegistration(APIView): 
    throttle_classes =() 
    serializer_class = UserRegistrationSerializer 

    def post(self, request, format=None): 
     event_type = "user_registration" 
     serializer = UserRegistrationSerializer(data=request.DATA, context={'request': request}) 
     try: 
      if serializer.is_valid(): 
       user_registration = serializer.save() 
       # save user_registration pieces in various places... 

Я также сказал в моем оригинальном посте:

Все это кажется более женатым к БД объектов, которые в данном случае является именно то, что я пытаюсь избежать.

Это утверждение также было неверным, поскольку видно, что методы создания и обновления не должны ничего сохранять в какой-либо БД.

Одно из предостережений заключается в том, что код является функциональным, но, очевидно, я просто обволакиваю некоторые из изменений DRF2.x-> 3.x, поэтому я мог бы делать это не-DRF-способом. Если да, то кто-то, кто знает, не стесняйтесь сказать мне, как это сделать лучше. :)

+1

В качестве головного устройства вы никогда не должны использовать значение str в качестве значения по умолчанию для функции, поскольку оно становится изменяемым и может привести к странному поведению - http://docs.python-guide.org/en/latest/ writing/gotchas/ – Alvin

+1

@Alvin То, что вы говорите, верно для изменяемых типов, но я почти 100% -ные строки python неизменяемы. – jackdbernier

+0

Простое примечание: «request.DATA» устарел в пользу «request.data» с версии 3.0 и полностью удален с версии 3.2. – Slipstream

Смежные вопросы