Django DRF - Access to field ForeignKey instance inside a custom serializer validator method

104 Views Asked by At

I'm currently having a bit of a conceptual headache over how best to reference the instance of a ForeignKey field inside a custom serializer validator method ...

To give an overview of the system. I have the following "Candidate" model, the imporant fields for this question are the user, job* and status fields.

from model_utils.fields import MonitorField, StatusField
from model_utils import Choices

class Candidate(models.Model):

    class Meta:
        ...

    STATUS = Choices(
        'matched',
        'approached',
        'invite_rejected',
        'invite_accepted',
        'reviewed',
        'interview_scheduled',
        'hired',
        'rejected'
    )

    user = models.ForeignKey('users.User', on_delete=models.CASCADE)

    job = models.ForeignKey('jobs.Job', related_name='candidates', on_delete=models.CASCADE)

    ... 

    status = StatusField(default='matched')

    ...

    def save(self, *args, **kwargs):
        super(Candidate, self).save(*args, **kwargs)

The status field for the Candidate can only be "updated" to a given value based on who they are, and what they're attempting to update the status to. Effectively, my outlined logic is as follows inside the serializer:

from rest_framework import serializers

from .candidates.models import Candidate

class CandidateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Candidate
        fields = '__all__'

    def validate_status(self, value):
        user = self.context['request'].user

        if user.is_anonymous:
            raise serializers.ValidationError("The requester must be logged in to make a change to the status field")

        # Ensure status value is in valid list of statuses
        if value not in [
            'matched',
            'approached',
            'invite_rejected',
            'invite_accepted',
            'reviewed',
            'interview_scheduled',
            'hired',
            'rejected'
        ]:
            raise serializers.ValidationError("The value provided does not match the prefedined status list")

        # Only the candidate owner can update to certain statuses?
        if value in [
            'invite_rejected',
            'invite_accepted',
        ]:
            if not self.user == user:
                raise serializers.ValidationError("You don't have the correct permission to update the status")

        if value in [
            'matched',
            'approached',
            'reviewed',
            'interview_scheduled',
            'hired',
            'rejected'
        ]:
            if user.is_anonymous or not self.job.organisation.is_admin(user) or not self.job.organisation.is_member(user):
                raise serializers.ValidationError("You don't have the correct permission to update the status")

        return value

That is to say, I can obtain the "user" doing the updating or creation of the Candidate model through the API from the serializer's self.context['request'].user.

I'm also checking that this user is at first, not anonymous.

What I want access to is the job field for the above serializer.

I'm thinking the "job" attribute for the serializer ... is accessible via self.job.

However, I'm thinking that this is going to return the primary key of the Job instance.

So...I wouldn't have access to the organisation attribue on the self.job field, because it is not technically an instance of the Job model:

user = self.context['request'].user

...

if not self.job.organisation.is_admin(user) or not self.job.organisation.is_member(user):
                raise serializers.ValidationError("You don't have the correct permission to update the status")

So, my question is, how should I correctly reference the Job instance associated to the Candidate I'm trying to reference?

*N.B. It's worth noting that the "job" field itself references a "Job" model, and this Job model in turn has a field of organisation which links to an organisation as outlined in the django-organizations package (reference here: https://github.com/bennylope/django-organizations/ if needed)

1

There are 1 best solutions below

0
On

Try something like this:

candidate = Candidate.objects.get(id=instance.pk)

job = Jobs.objects.filter(candidates__pk=candidate.pk)

You need to retrieve the job instance from a query, then you can use it as you want. For more complex things you can look at get_serializer_context(self)then you can pass attributes to the serializers as kwargs.. Difficult to say more without viewing the whole stuff and the view