1

I have six models, they are below:

class Certificate(DateTimeLog):
    name = models.TextField(max_length=255)


class Vacancy(DateTimeLog):
    name = models.CharField(max_length=255)
    parent_position = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True,
                                        related_name='sub_positions')


class Region(DateTimeLog):
    name = models.CharField(max_length=255)


class MaritalStatus(DateTimeLog):
    name = models.CharField(max_length=255)


class Candidate(DateTimeLog):
    pin = models.CharField(max_length=16, unique=True)
    first_name = models.CharField(max_length=64, blank=True, null=True)
    last_name = models.CharField(max_length=64, blank=True, null=True)
    marital_status = models.ForeignKey(MaritalStatus, on_delete=models.SET_NULL, null=True, blank=True)
    certificate = models.ManyToManyField(Certificate, blank=True)


class Candidacy(DateTimeLog):
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE)
    vacancy = models.ForeignKey(Vacancy, on_delete=models.CASCADE)
    work_region = models.ForeignKey(Region, on_delete=models.SET_NULL, null=True, blank=True)

Now I want to handle, if candidate record exists(I am checking it with pin), then check and update Candidate related data. If a candidate does not exist create it. After the candidate is created or updated assign it to the candidacy. My Serializer looks like below:

class CandidateSerializer(serializers.ModelSerializer):
    marital_status = MaritalStatusSerializer(required=False)
    certificate = CertificateSerializer(many=True, required=False)

    def create(self, validated_data):
        marital_status_data = validated_data.pop("marital_status")
        certificate_data = validated_data.pop("certificate")
        candidate = Candidate.objects.create(**validated_data)

        ms_o = MaritalStatus.objects.get(name=marital_status_data["name"])
        candidate.marital_status = ms_o

        for certificate in certificate_data:
            certificate_o = Certificate.objects.create(**certificate)
            candidate.certificate.add(certificate_o)

        candidate.save()
        return candidate

    class Meta:
        model = Candidate
        fields = '__all__'
        depth = 1


class CandidacySerializer(serializers.ModelSerializer):
    candidate = CandidateSerializer()
    vacancy = VacancySerializer()
    work_region = RegionSerializer()

    def create(self, validated_data):
        candidate_s = CandidateSerializer()
        candidate_data = validated_data.pop('candidate')

        vacancy_data = validated_data.pop('vacancy')
        work_region_data = validated_data.pop('work_region')

        vac_o = Vacancy.objects.get(name=vacancy_data['name'])
        wr_o = Region.objects.get(name=work_region_data['name'])
        candidate_o = candidate_s.create(validated_data=candidate_data)
        validated_data.update({
            'candidate': candidate_o,
            'vacancy': vac_o,
            'work_region': wr_o
        })
        candidacy = Candidacy.objects.create(**validated_data)
        return candidacy

    class Meta:
        model = Candidacy
        fields = '__all__'
        depth = 1

Currently, I am able to create it with the post request. Am I need to check it explicitly or it is possible to achieve it inside the serializer?

Mamed
  • 95
  • 4
  • 16

3 Answers3

0

so you have a more straightforward option. There is a function called get or create, which will check if the object exists and return it else make it. similar question can be found here Another use of the same question By the way, if this pin is sensitive, I recommend encrypting it.

shaked
  • 561
  • 7
  • 19
0

Since you have already made pin unique with

pin = models.CharField(max_length=16, unique=True)

there is no chance of having two similar pins. and now to check a candidate based on pin you will have to manually do something like this in your create method.

if Candidate.objects.filter(pin = revievedPinData):
    here candidate is already present so update the information information
    and again check if Canditate is in Candidacy or not
    first get the candidate object
    c = Candidate.objects.get(pin = revievedPinData)
    then
    if Candidacy.objects.filter(candidate = c):
       if true candidate is already assigned and the updated value of candidate will reflect here
    else: create the Candidacy with the current candidate and other values
else:
    if candidate is not there (from the given pin)
    create a new candidate
    aa = candidate.objects.create()
    create a new Candidacy with candidate aa
    Candidacy.objects.create(candidate=aa, **otherdata)
     

  
Ranu Vijay
  • 1,137
  • 9
  • 18
0

First of all, you can use update_or_create in your CandidateSerializer like this:

class CandidateSerializer(serializers.ModelSerializer):
    marital_status = MaritalStatusSerializer(required=False)
    certificate = CertificateSerializer(many=True, required=False)

    def create(self, validated_data):
        marital_status_data = validated_data.pop("marital_status")
        certificate_data = validated_data.pop("certificate")
        candidate, created = Candidate.objects.update_or_create(
            pin=validated_data['pin'],
            **validated_data
        )

        ms_o = MaritalStatus.objects.get(name=marital_status_data["name"])
        candidate.marital_status = ms_o

        for certificate in certificate_data:
            certificate_o = Certificate.objects.create(**certificate)
            candidate.certificate.add(certificate_o)

        candidate.save()
        return candidate

    class Meta:
        model = Candidate
        fields = '__all__'
        depth = 1

Secondly, you should not call the method create() directly. You have to use save() instead. You have to replace:

candidate_s = CandidateSerializer()
candidate_o = candidate_s.create(validated_data=candidate_data)

by

candidate_s = CandidateSerializer(data=candidate_data)
candidate_o = candidate_s.save()

You can read more about saving instances here.

Oleksii Tambovtsev
  • 2,666
  • 1
  • 3
  • 21