4

I'm writing a contacts service in Django-REST-Framework. I have a Contact Model and a PhoneNumber Model which has a foreignKey field that shows which contact does it belong to. Here are my models:

class ContactModel(models.Model):
    firstname = models.CharField(max_length=50, blank=False)
    lastname = models.CharField(max_length=50, blank=False)

class PhoneNumber(BaseModel):
    country_code = models.CharField(max_length=VERY_SHORT_STRING_SIZE, blank=False)
    phone_number = models.CharField(max_length=SHORT_STRING_SIZE, blank=False, null=False)
    label = models.CharField(max_length=NORMAL_STRING_SIZE, blank=True, default='')
    related_contact = models.ForeignKey(to='ContactModel', on_delete=models.CASCADE)

I want to make a CRUD api for my Contacts. I have a ModelViewSet and a ModelSerializer for that. serializer codes is as follows:

class ContactSerializer(serializers.ModelSerializer):
    phonenumber_set = PhoneSerializer(many=True, required=False)
        class Meta:
            model = ContactModel
            fields = '__all__'

class PhoneSerializer(serializers.ModelSerializer):
    class Meta:
        model = PhoneNumber
        fields = ['id', 'country_code', 'phone_number', 'label']

As it's been specified here I should override update and create methods in order to update and create PhoneNumbers of my Contact.

The problem is that if I override those functions I have to use them like this:

class ContactSerializer(serializers.ModelSerializer):
    ...
    def create(self, validated_data):
        # some code for creating both PhoneNumber and Contact


    def update(self, instance, validated_data):
        # some code for updating both PhoneNumber and Contact

and unfortunately, 'validated_data' argument doesn't bring the 'id' of my PhoneNumber objects, because 'id' fields are AutoFields and AutoFields will be read_only in DRF (it's explained Here).

Is there a way for me to have access to my 'id' field in my update method? (kinda need it badly)

Thanks.

Mahmoud Adel
  • 1,262
  • 2
  • 13
  • 23
m.farhang
  • 41
  • 1
  • 4

1 Answers1

0

Just loop over instance.phonenumber_set.all() at your update() method and you will have complete access to those related objects.

for ex:

def update(self, instance, validated_data):
    for phonenumber in instance.phonenumber_set.all():
        # do what you want with phonenumber, like phonenumber.id

instance is the current object that is being updated at your serializer and it is being passed as an argument to update() as you can see, so you can access and do anything with it as you normally do.

Tip:

It's better to add related_name to related_contact to make it better readability, also change related_contact to contacts. related_name is used for selecting reverse relations as we did just like now.

I think it's better to do so:

contacts = models.ForeignKey(to='ContactModel', on_delete=models.CASCADE, related_name='phonenumbers')

so instead of using phonenumber_set it will be phonenumbers for better readability but the name with _map still valid too, see this answer for more info about related_name

Mahmoud Adel
  • 1,262
  • 2
  • 13
  • 23
  • Don't think this could help. I need to have one of my PhoneNumbers id, not my instance id. – m.farhang Apr 29 '21 at 10:46
  • sorry, I thought you were asking about the object itself. I have updated my answer, check it out. – Mahmoud Adel Apr 29 '21 at 11:06
  • I truly appreciate your help, but I have to say that unfortunately this is not the answer, again. by using "instance.phonenumbers_set.all()" I will get all phone_numbers currently stored in database for my contact. and what I want, is the passed ID of to-be-updated phone_numbers, which have just been sent from client. – m.farhang May 01 '21 at 08:51
  • okay, now I get your goal, but, can you share your request data? generally `instance` is the object that will be updated so you should look there but let's see. – Mahmoud Adel May 01 '21 at 11:58