Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pagination - I #54

Merged
merged 10 commits into from
Jan 24, 2024
208 changes: 167 additions & 41 deletions apps/jobs/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import jwt
import uuid
from re import search
from django.db.models import Count
import django.core.exceptions
from django.db.utils import IntegrityError
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import status, viewsets
from rest_framework.decorators import action
Expand Down Expand Up @@ -72,13 +74,26 @@ def list(self, request):
except django.core.exceptions.ValidationError as err:
return response.create_response(err.messages, status.HTTP_404_NOT_FOUND)
else:
# Use Paginator for the queryset
page_number = request.GET.get("page", 1)
paginator = Paginator(jobs_data, 5) # 5 items per page
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use it from constant, store it in constant.


try:
jobs_data = paginator.page(page_number)
except PageNotAnInteger:
jobs_data = paginator.page(1)
except EmptyPage:
return response.create_response([], status.HTTP_200_OK)

serialized_job_data = self.serializer_class(
jobs_data, many=True, context={"request": request}
)

# get number of applicants
if serialized_job_data:
serialized_job_data = JobViewSets.get_number_of_applicants(serialized_job_data)
serialized_job_data = JobViewSets.get_number_of_applicants(
serialized_job_data
)

return response.create_response(
serialized_job_data.data, status.HTTP_200_OK
Expand Down Expand Up @@ -129,7 +144,6 @@ def details(self, request, *args, **kwargs):
)
return response.create_response(serialized_job_data.data, status.HTTP_200_OK)


@staticmethod
def get_number_of_applicants(serialized_data):
"""
Expand All @@ -153,7 +167,7 @@ def get_number_of_applicants(serialized_data):
jobdata.update({"Number of Applicants": number_of_applicants})

return serialized_data

@staticmethod
def get_active_jobs_count(serialized_company_data):
"""
Expand All @@ -162,10 +176,12 @@ def get_active_jobs_count(serialized_company_data):
"""

for company in serialized_company_data.data:
jobs_belong_to_company = Job.objects.filter(company_id=company.get("company_id"))
active_jobs = sum(1 for job in jobs_belong_to_company if job.is_active)
company.update({"Active Jobs": active_jobs})

jobs_belong_to_company = Job.objects.filter(
company_id=company.get("company_id")
)
active_jobs = sum(1 for job in jobs_belong_to_company if job.is_active)
company.update({"Active Jobs": active_jobs})

return serialized_company_data

@action(detail=True, methods=["get"])
Expand Down Expand Up @@ -319,38 +335,148 @@ def featured_jobs(self, request):
"""

# past 3 weeks datetime specified for featured jobs (can be modified as per use)
past_3_weeks_datetime = datetime_safe.datetime.now(tz=timezone.utc) - timedelta(days=18)
past_3_weeks_datetime = datetime_safe.datetime.now(tz=timezone.utc) - timedelta(
days=18
)
Parth858 marked this conversation as resolved.
Show resolved Hide resolved

# get the jobs_data and sort it in DESC order
# `-` with column name indicates to return the result in DESC order
try:
jobs_data = Job.objects.filter(
created_at__gt=past_3_weeks_datetime,
is_active=True
created_at__gt=past_3_weeks_datetime, is_active=True
).order_by("-created_at")

jobs_posted_within_3_weeks = JobSerializer(jobs_data, many=True)

# find out how many jobs were posted within past_3_weeks
jobs_posted_within_3_weeks = JobViewSets.get_number_of_applicants(jobs_posted_within_3_weeks)
jobs_posted_within_3_weeks = JobViewSets.get_number_of_applicants(
jobs_posted_within_3_weeks
)

# find 5 jobs with maximum number of applicants
featured_jobs = sorted(
jobs_posted_within_3_weeks.data,
key=lambda k: (k.get('Number of Applicants')),
reverse=True
key=lambda k: (k.get("Number of Applicants")),
reverse=True,
)

return response.create_response(featured_jobs[0:5], status.HTTP_200_OK)
except Exception:
return response.create_response(
featured_jobs[0:5],
status.HTTP_200_OK
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)

@action(detail=False, methods=["get"])
def get_posted_jobs(self, request):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(update sample response where per page items are 3 )

request: http://localhost:8000/jobs/get_posted_jobs/?page=2
response:  "data": [
        {
            "job_id": "beb1b9dc-5106-423c-95e8-efbbc0103d8b",
            "job_role": "Security Analysist II",
            "location": "Mumbai",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 0,
            "created_at": "2024-01-11T18:07:00.626348Z",
            "updated_at": "2024-01-11T18:07:00.626348Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "30000.00",
            "qualifications": "OWASP",
            "vacency_position": 5,
            "industry": "IT",
            "category": "Security",
            "is_active": true,
            "company": "d937d8f3-6c54-4bf2-b652-e44597910693",
            "description": {
                "About": "You will be responsible for designing, developing, testing, and deploying distributed machine learning systems and large-scale solutions for our world-wide customer base",
                "Job Responsibilities": "No Job Responsibilities provided",
                "Skills Required": "No skills details provided",
                "Educations/Certifications": "No Education details provided"
            },
            "Number of Applicants": 0
        },
        {
            "job_id": "c8fddf51-644e-42a7-8ef1-d91178dbf22d",
            "job_role": "Junior Developer",
            "location": "Mumbai",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 3,
            "created_at": "2024-01-19T12:41:51.821701Z",
            "updated_at": "2024-01-19T12:41:51.829724Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "30000.00",
            "qualifications": "OWASP",
            "vacency_position": 5,
            "industry": "IT",
            "category": "Security",
            "is_active": true,
            "company": "d937d8f3-6c54-4bf2-b652-e44597910693",
            "description": {
                "About": "Manage the group of people as well as make the upcomming task secure.",
                "Job Responsibilities": "No Job Responsibilities provided",
                "Skills Required": "No skills details provided",
                "Educations/Certifications": "No Education details provided"
            },
            "Number of Applicants": 0
        },
        {
            "job_id": "fc52dbad-8a83-4276-99be-a61104234ff9",
            "job_role": "Unit Tester",
            "location": "California",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 0,
            "created_at": "2024-01-11T18:02:26.112538Z",
            "updated_at": "2024-01-11T18:02:26.112538Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "20000.00",
            "qualifications": "Commerces, Data Managment",
            "vacency_position": 3,
            "industry": "IT",
            "category": "Testing",
            "is_active": true,
            "company": "b2490ff9-cb56-4627-9653-921051267074",
            "description": {
                "About": "You will be responsible for designing, developing, testing, and deploying distributed machine learning systems and large-scale solutions for our world-wide customer base",
                "Job Responsibilities": "No Job Responsibilities provided",
                "Skills Required": "No skills details provided",
                "Educations/Certifications": "No Education details provided"
            },
            "Number of Applicants": 0
        }
    ]
}

"""
API: localhost:8000/jobs/get_posted_jobs/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base_url

This method returns a list of jobs where is_posted is True.
"""

# Get only posted jobs
posted_jobs_data = Job.objects.filter(posted=True)
page_number = request.GET.get("page", 1) # used paginator for queryset
paginator = Paginator(posted_jobs_data, 2) # per page 2 items

try:
posted_jobs_data = paginator.page(page_number)
except PageNotAnInteger:
posted_jobs_data = paginator.page(1)
except EmptyPage:
return response.create_response([], status.HTTP_200_OK)

serialized_posted_jobs_data = self.serializer_class(
posted_jobs_data, many=True, context={"request": request}
)

# Add number of applicants to the serialized data
if serialized_posted_jobs_data:
serialized_posted_jobs_data = JobViewSets.get_number_of_applicants(
serialized_posted_jobs_data
)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
serialized_posted_jobs_data.data, status.HTTP_200_OK
)

@action(detail=False, methods=["get"])
def get_job_categories(self, request):
"""
API: /api/v1/jobs/get_job_categories/
This method returns a list of distinct job categories.
If a 'category' parameter is provided in the query string,
it filters jobs by the specified category.
"""

# Check if 'category' parameter is provided in the query string
category = request.query_params.get("category", None)

if category:
# Filter jobs by the specified category
jobs_data = Job.objects.filter(category=category)
serialized_jobs_data = JobSerializer(
jobs_data, many=True, context={"request": request}
)
return response.create_response(
serialized_jobs_data.data, status.HTTP_200_OK
)
else:
# Get distinct job categories
job_categories = Job.objects.values_list("category", flat=True).distinct()
serialized_job_categories = list(job_categories)

return response.create_response(
serialized_job_categories, status.HTTP_200_OK
)

@action(detail=False, methods=["get"])
def get_jobs(self, request):
Copy link
Contributor Author

@Parth858 Parth858 Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Retrive jobs as per quary parameter also jobs where exp <=3.
request: http://localhost:8000/jobs/get_jobs/?category=Security&experience=3

response: { {
            "job_id": "beb1b9dc-5106-423c-95e8-efbbc0103d8b",
            "job_role": "Security Analysist II",
            "location": "Mumbai",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 0,
            "created_at": "2024-01-11T18:07:00.626348Z",
            "updated_at": "2024-01-11T18:07:00.626348Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "30000.00",
            "qualifications": "OWASP",
            "vacency_position": 5,
            "industry": "IT",
            "category": "Security",
            "is_active": true,
            "company": "d937d8f3-6c54-4bf2-b652-e44597910693",
            "description": {
                "About": "You will be responsible for designing, developing, testing, and deploying distributed machine learning systems and large-scale solutions for our world-wide customer base",
                "Job Responsibilities": "No Job Responsibilities provided",
                "Skills Required": "No skills details provided",
                "Educations/Certifications": "No Education details provided"
            }
        },
        {
            "job_id": "c8fddf51-644e-42a7-8ef1-d91178dbf22d",
            "job_role": "Junior Developer",
            "location": "Mumbai",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 3,
            "created_at": "2024-01-19T12:41:51.821701Z",
            "updated_at": "2024-01-19T12:41:51.829724Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "30000.00",
            "qualifications": "OWASP",
            "vacency_position": 5,
            "industry": "IT",
            "category": "Security",
            "is_active": true,
            "company": "d937d8f3-6c54-4bf2-b652-e44597910693",
            "description": {
                "About": "Manage the group of people as well as make the upcomming task secure.",
                "Job Responsibilities": "No Job Responsibilities provided",
                "Skills Required": "No skills details provided",
                "Educations/Certifications": "No Education details provided"
            }
  1. Dynamically retriving of jobs as per the queary updation
request: http://localhost:8000/jobs/get_jobs/?job_type=full time
response: {
            "job_id": "be5f509a-855a-4de8-b13e-7cb6cf2243fc",
            "job_role": "Product Manager",
            "location": "California",
            "post_date": "2023-10-11",
            "posted": true,
            "experience": 0,
            "created_at": "2024-01-11T17:58:36.746918Z",
            "updated_at": "2024-01-11T17:58:36.746918Z",
            "employer_id": "5e1f2925-9deb-492f-8a06-f451daf9310a",
            "job_type": "full time",
            "salary": "20000.00",
            "qualifications": "Commerces, Data Managment",
            ...

"""
API: /api/v1/jobs/get_jobs/
This method retrieves jobs based on dynamic filters such as
category, job type, experience, and qualification provided in the query parameters.
It also includes the count of active jobs for each filter.
"""

# Extract filters from query parameters
filters = {}
category = request.query_params.get("category", None)
job_type = request.query_params.get("job_type", None)
experience = request.query_params.get("experience", None)
qualification = request.query_params.get("qualification", None)

if category:
filters["category"] = category
if job_type:
filters["job_type"] = job_type
if experience:
filters["experience__gte"] = int(
experience
) # Filter jobs with experience greater than or equal to specified value
if qualification:
filters[
"qualifications__icontains"
] = qualification # Case-insensitive search for qualifications

# Get the filtered jobs
filtered_jobs_data = Job.objects.filter(**filters, is_active=True)

# If no jobs match the filters, return a specific response
if not filtered_jobs_data.exists():
return response.create_response(
"Sorry, currently no jobs available as per your request",
status.HTTP_200_OK,
)

# Serialize the filtered job data
serialized_filtered_jobs_data = JobSerializer(
filtered_jobs_data, many=True
).data

return response.create_response(
serialized_filtered_jobs_data, status.HTTP_200_OK
)


class UserViewSets(viewsets.ModelViewSet):
"""
User object viewsets
Expand Down Expand Up @@ -498,16 +624,16 @@ def update(self, request, *args, **kwargs):
UserSerializer(user_data).data, status.HTTP_200_OK
)

@action(detail=False, methods=['get'])
@action(detail=False, methods=["get"])
def get_profile_details(self, request):
"""
API: /api/v1/user/myProfile
Returns user profile data in the response.
Returns user profile data in the response.
This method gets the user_id from "access-token".
"""

# Get the value from Access-Token header
if access_token:=request.headers.get(response.ACCESS_TOKEN, None):
if access_token := request.headers.get(response.ACCESS_TOKEN, None):
try:
# decode JWT Token; for any issues with it, raise an exception
decoded_user_access_token = jwt.decode(
Expand All @@ -516,29 +642,25 @@ def get_profile_details(self, request):
user_id = decoded_user_access_token.get(values.USER_ID, None)
if not user_id:
raise Exception

# get user data
user_data = self.queryset.filter(user_id=user_id)
if user_data:
serialized_user_data = self.serializer_class(user_data, many=True)
return response.create_response(
serialized_user_data.data,
status.HTTP_200_OK
serialized_user_data.data, status.HTTP_200_OK
)
else:
return response.create_response(
response.USER_DATA_NOT_PRESENT,
status.HTTP_404_NOT_FOUND
response.USER_DATA_NOT_PRESENT, status.HTTP_404_NOT_FOUND
)
except Exception:
return response.create_response(
response.ACCESS_TOKEN_NOT_VALID,
status.HTTP_400_BAD_REQUEST
response.ACCESS_TOKEN_NOT_VALID, status.HTTP_400_BAD_REQUEST
)
else:
return response.create_response(
response.ACCESS_TOKEN_NOT_PRESENT,
status.HTTP_401_UNAUTHORIZED
response.ACCESS_TOKEN_NOT_PRESENT, status.HTTP_401_UNAUTHORIZED
)

@action(detail=True, methods=["get"])
Expand Down Expand Up @@ -619,7 +741,7 @@ class CompanyViewSets(viewsets.ModelViewSet):

def list(self, request):
"""
Method to return a list of companies available,
Method to return a list of companies available,
Along with the count of active jobs present in the company
"""

Expand All @@ -630,17 +752,18 @@ def list(self, request):

# get number of applicants
if serialized_company_data:
serialized_company_data = JobViewSets.get_active_jobs_count(serialized_company_data)
serialized_company_data = JobViewSets.get_active_jobs_count(
serialized_company_data
)

return response.create_response(
serialized_company_data.data, status.HTTP_200_OK
)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)

def retrieve(self, request, pk=None):
"""
retrieve the data of given company id
Expand All @@ -657,12 +780,15 @@ def retrieve(self, request, pk=None):
company_data = Company.objects.filter(company_id=pk)
serialized_company_data = self.serializer_class(company_data, many=True)
if serialized_company_data:
serialized_company_data = JobViewSets.get_active_jobs_count(serialized_company_data)
return response.create_response(serialized_company_data.data, status.HTTP_200_OK)
serialized_company_data = JobViewSets.get_active_jobs_count(
serialized_company_data
)
return response.create_response(
serialized_company_data.data, status.HTTP_200_OK
)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)

@action(detail=False, methods=["get"])
Expand Down Expand Up @@ -751,4 +877,4 @@ def list(self, request, *args, **kwargs):
else:
return super().list(request, *args, **kwargs)
else:
return super().list(request, *args, **kwargs)
return super().list(request, *args, **kwargs)