sagar limbu
sagar limbu

Reputation: 1262

How to serialize foreignkey in Django Rest Framwork?

I have jobs model and categories model and they have one to many relationship. so I want to get the details of category as well when i pull the job model.

Abstract Job Model

class JobAbstractModel(models.Model):
    title = models.CharField(max_length=150)
    no_of_vacancy = models.PositiveIntegerField()
    offered_salary = models.CharField(max_length=200)
    deadline = models.DateTimeField()
    education_level = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    description_points = models.TextField(blank=True)
    skills = models.TextField()
    other_specification = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    updated_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='+')
    is_active = models.BooleanField(default=1)

    class Meta:
        abstract = True

Job Model

class Job(JobAbstractModel):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='categories')
    job_level = models.CharField(max_length=50, choices=JOB_LEVEL_CHOICES, default='Mid')
    employment_type = models.CharField(max_length=50, choices=EMPLOYEMENT_TYPE_CHOICES, default='Full')
    experienced_required = models.FloatField()
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='jobs_created_by')

    def __str__(self):
        return self.title

Category Model

class Category(models.Model):
    name = models.CharField(max_length=150)
    is_active = models.BooleanField(default=1)
    image = models.ImageField(upload_to='categories_images/')

    def __str__(self):
        return self.id + ":"+self.name

Serializers.py

class CategorySerializer(serializers.ModelSerializer):
    image = serializers.SerializerMethodField()

    class Meta:
        model = Category
        fields = "__all__"

    def get_image(self, category):
        request = self.context.get('request')
        image_url = category.image.url
        return request.build_absolute_uri(image_url)


class JobOverViewSerializer(serializers.ModelSerializer):
    #category = serializers.CharField(source='category.name', read_only=True)
    categories = CategorySerializer(read_only=True, many=True)

    class Meta:
        model = Job
        fields = ['id', 'no_of_vacancy', 'employment_type', 'experienced_required', 'categories']

jobs.py

class JobCategoriesView(APIView):
    def get(self, request):
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True, context={'request': request})
        return Response(serializer.data)


class JobOverView(APIView):

    def get(self, request):
        jobs = Job.objects.filter(deadline__gte=date.today())
        serializer = JobOverViewSerializer(jobs, many=True)
        return Response(serializer.data)

The output json is:

{
    "status": "success",
    "message": "Data Retrieved Successfully",
    "data": [
        {
            "id": 1,
            "no_of_vacancy": 1,
            "employment_type": "Full",
            "experienced_required": 1.0
        }
    ]
}

so, all i am wondering is where is the categories data. I have categories serializer while fetching jobs. so am i doing something wrong that avoids pulling categories data?

Upvotes: 0

Views: 44

Answers (3)

JPG
JPG

Reputation: 88689

As per your model definition, for each Job instance, there will be only one Category in the database.

So, change your JobOverViewSerializer as

class JobOverViewSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True) # remove `many=True` as well as change the field name to `category`

    class Meta:
        model = Job
        fields = [
            'id',
            'no_of_vacancy',
            'employment_type',
            'experienced_required',
            'category' # use `category` instead of `categories`
        ]

Upvotes: 2

Petr Hofman
Petr Hofman

Reputation: 172

The problem lies in your Models definition. Defined like this your Job object has only one category whereas your Category object can have multiple jobs (named illogically "categories"). You should define your models this way:

class Job(JobAbstractModel):
    job_level = models.CharField(max_length=50, choices=JOB_LEVEL_CHOICES, default='Mid')
    employment_type = models.CharField(max_length=50, choices=EMPLOYEMENT_TYPE_CHOICES, default='Full')
    experienced_required = models.FloatField()
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='jobs_created_by')

    def __str__(self):
        return self.title

class Category(models.Model):
    job = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='categories')
    name = models.CharField(max_length=150)
    is_active = models.BooleanField(default=1)
    image = models.ImageField(upload_to='categories_images/')

    def __str__(self):
        return self.id + ":"+self.name

Or maybe you would want to use Many-to-many field so that one job can have multiple categories and one category can be used for multiple jobs.

Upvotes: 1

Shinra tensei
Shinra tensei

Reputation: 1293

The serializer is looking for categories in the Job model. There isn't any field called categories, thus there will be no data to be returned.

You need to use category = CategorySerializer(read_only=True, many=True) in the serializer. Notice that it's the same you've already done, just that the name is the same as the name of the field in the Job model. Also, in the Meta, you have to modify the last field: fields = ['id', 'no_of_vacancy', 'employment_type', 'experienced_required', 'category'].

As a side note, the category foreign key field in the Job model is not well made. You want its related name to be the name to identify the model in the opposite direction. With your code as an example, if Job has a foreign key pointing to Category, you want its related name to be jobs, because a Category can be related to several Jobs.

Upvotes: 1

Related Questions