TIL
Web Dev Bootcamp TIL Day-50(DRF Serializers / Query Parameters)
frannyk
2022. 6. 24. 22:18
- Query parameters are a defined set of parameters attached to the end of a url.
- They are extensions of the URL that are used to help define specific content or actions based on the data being passed.
- To append query params to the end of a URL, a ‘?’ Is added followed immediately by a query parameter.
- Let's say we want to search for jobs posts that require certain skills using query parameters:
- First, let's make sure that skillsets and job posts are in a many-to-many relationship
- Notice that we can use an intermediate table to manage the relationship betwen the two models:
class SkillSet(models.Model):
name = models.CharField(max_length=128)
job_posts = models.ManyToManyField('JobPost', through='JobPostSkillSet')
class Meta:
db_table = 'skill_sets'
class JobPostSkillSet(models.Model):
skill_set = models.ForeignKey('SkillSet', on_delete=models.SET_NULL, null=True)
job_post = models.ForeignKey('JobPost', on_delete=models.SET_NULL, null=True)
class JobPost(models.Model):
job_type = models.ForeignKey(JobType, on_delete=models.SET_NULL, null=True)
company = models.ForeignKey('Company', on_delete=models.SET_NULL, null=True)
job_description = models.TextField()
salary = models.IntegerField()
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'job_posts'
- Query Parameters and Reverse Lookups
- First we want to return the queryset of JobPostSkillSet objects that fit our search criteria
- From that queryset, we then return the queryset of corresponding JobPost objects
- In this particular example, let's say we send skills = ['node', 'postgresql'] as query parameters
- These skillsets have id values of 4 and 5 respectively.
- Notice that our JobPostSkillSet queryset returns instances 1, 5 and 6 even though instance 5 does not contain our skillset parameter.
- This is due to the fact that JobPost instance 3 requires skills = ['mysql', 'node'] such that the JobPostSkillSet queryset will return the JobPostSkillSet instance that takes JobPost instance 3 and SkillSet instance 3 as Foreign Keys.
class JobPostView(APIView):
def get(self, request):
# we can receive all query parameter values w/ the same key values
# and store them into a list variable
skills = request.query_params.getlist('skills', '')
# if we wish to make a query using multiple conditions from a list
query = Q()
for skill in skills:
query.add(Q(skill_set__name=skill), Q.OR)
job_skills = JobPostSkillSet.objects.filter(query)
# SELECT * FROM jobpostskillset WHERE (skill_set__name='node') OR (skill_set__name='postgresql'))
job_posts = JobPost.objects.filter(
id__in=[job_skill.job_post.id for job_skill in job_skills]
)
if job_posts.exists():
serializer = JobPostSerializer(job_posts, many=True)
return Response(serializer.data)
- Our final output will be serialized data of JobPost instance 1 and 3:
[
{
"id": 1,
"position_type": "permanent",
"company": {
"id": 1,
"company_name": "company1"
},
"job_description": "jd1",
"salary": 100000000,
"skiilsets": [
"postgresql"
]
},
{
"id": 3,
"position_type": "permanent",
"company": {
"id": 3,
"company_name": "company3"
},
"job_description": "jd3",
"salary": 100000000,
"skiilsets": [
"mysql",
"node"
]
}
]
- JobType and Company are both in a many-to-one relationship with JobPost.
- When creating model instances, we must save its Foreign Key object instances in a separate manner after the request data has been validated.
class JobPostView(APIView):
def post(self, request):
job_type = request.data.get("job_type", None)
company_name = request.data.get("company_name", None)
try:
job_type_instance = JobType.objects.get(job_type=job_type)
except JobType.DoesNotExist:
return Response({"message": "Please enter a valid job type"}, status=status.HTTP_400_BAD_REQUEST)
try:
Company.objects.get(company_name=company_name)
except Company.DoesNotExist:
company_instance = Company(company_name=company_name).save()
job_serializer = JobPostSerializer(data=request.data)
if job_serializer.is_valid():
job_serializer.save(company=company_instance, job_type=job_type_instance)
return Response(status=status.HTTP_200_OK)
return Response(job_serializer.errors, status=status.HTTP_400_BAD_REQUEST)