Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you make a Django Rest Framework serializer bi-directional

I have an angular app that presents a form with contact data and a list of contact numbers. Each contact can have N numbers and each of those numbers has a type (cell,home,work...) The code below will send the json to the angular app just fine and I can deal with it there including adding new numbers, removing numbers ..... However when DRF gets the exact same format json back, it can't deserialize it. It throws off this error:

AttributeError: 'Contact' object has no attribute 'numbers'

which is totally valid, but the serializer DOES have that field and should be able to hang onto those values so I can save them after I save the contact.

If I do something totally hokey like this in the update method:

self.object = self.get_object_or_none()
self.object.numbers = []

I can eliminate that error, but then it throws off these kind of errors:

{'numbers': [
    {u'non_field_errors': [u'Cannot create a new item, only existing items may be updated.']}, 
    {u'non_field_errors': [u'Cannot create a new item, only existing items may be updated.']}, 
    {u'non_field_errors': [u'Cannot create a new item, only existing items may be updated.']}
]}

The first two phone numbers aren't new, they have id fields and came from the db, the third one is new, I'm trying to add it.

Here is the code. Surely this isn't that bizarre a way to do things. Is Django Rest Framework what I should be using? I keep running into show stoppers like this that seem to be the documented way to do things, but then they blow up spectacularly.

class PhoneTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = PhoneType

class ContactPhoneSerializer(serializers.ModelSerializer):
    number_type = PhoneTypeSerializer(source='number_type')
    class Meta:
        model = ContactPhone
        depth = 1
        exclude = ('owner',)

class ContactSerializer(serializers.ModelSerializer):
    numbers = ContactPhoneSerializer(source='number_set', many=True, required=False)
class Meta:
    model = Contact

How do I deserialize this data so I can save it?

like image 265
boatcoder Avatar asked Jan 12 '14 03:01

boatcoder


People also ask

Do we need Serializers in Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

What does serializer Is_valid do?

The .is_valid() method takes an optional raise_exception flag that will cause it to raise a serializers.ValidationError exception if there are validation errors.

What is Serializers SerializerMethodField ()?

SerializerMethodField. This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. Signature: SerializerMethodField(method_name=None)

How do you pass extra context data to Serializers in Django REST framework?

In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.


1 Answers

I had the same issue and solved it by adding to the serializer some flags. In your case it should be something like:

number_type = PhoneTypeSerializer(source='number_type',  many=True, required=False, allow_add_remove=True, read_only=False)

A bit late, but maybe it still helps. Found this suggestion here: Updating m2m not possible when using serializers as fields

like image 194
Vlad Avatar answered Nov 10 '22 10:11

Vlad