Reputation: 1262
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
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
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
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 Job
s.
Upvotes: 1