Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reuse Existing Object in Django Rest Framework Nested Serializer

How do I go about re-using the referenced object when using nested Serializers in the drf:

Let's say I have the following two Models:

class Address(models.Model):
    address_line = models.CharField(max_length=45)

class Person(models.Model):
    name = models.CharField(max_length=45)
    address = models.ForeignKey(Address)

with Serializers:

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address

class PersonSerializer(serializers.ModelSerializer):
    address = AddressSerializer()

    class Meta:
        model = Person

Right now the Serializers handle creating both the Address and the Person together. e.g, when I post the following:

{
    'name': 'Alex',
    'address': {
        'address_line': "1 Here"
    }
}

a Person is created and an Address is created with the Person pointing to the newly created Address.

What is the best way to NOT create a new Address but to reuse an existing Address if there is already an Address with a given address_line? i.e if I wanted to make the address_line field unique? (this object re-use is sometimes called "interning")

What about if there were two address fields address_line1 and address_line2 and I wanted to reuse the Address object if there already exists an Address with both of those fields (i.e. unique_together=(address_line1, address_line2))?

like image 552
Alex Rothberg Avatar asked Oct 08 '14 00:10

Alex Rothberg


People also ask

How do I pass extra data to a serializer?

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.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

Is it necessary to use Serializers in Django?

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 is serializer Is_valid?

is_valid perform validation of input data and confirm that this data contain all required fields and all fields have correct types. If validation process succeded is_valid set validated_data dictionary which is used for creation or updating data in DB.


1 Answers

Recently I faced a similar problem, solved it using the following approach (the code has not been tested, its just for reference):

class PersonSerializer(serializers.ModelSerializer):
    address = AddressSerializer()

    class Meta:
        model = Person

    def create(self, validated_data):
        # pop the validated user data
        # assuming its a required field,
        # it will always be there in validated_data
        address = validated_data.pop('address')

        try:
            address = Address.objects.get(address_line=address.get('address_line'))
        except ObjectDoesNotExist:
            address_serializer = AddressSerializer(data=address)
            address_serializer.is_valid(raise_exception=True)
            address = address_serializer.save()
        else:
            # save the user and update the validated_data for setting up profile
            validated_data['address'] = address

        return super(PersonSerializer, self).create(validated_data)

Hope this helps :)

like image 94
Ankit Popli Avatar answered Oct 25 '22 01:10

Ankit Popli