# Find best candidates in efficient way, Django

I'm beginner in django and python. I have models :

 class Employee(models.Model):
full_name = models.CharField(max_length = 64)
title = models.CharField(max_length = 64)

def __str__(self):
return f"{self.full_name} ( {self.title} )"

class Skill(models.Model):
name = models.CharField(max_length = 64)

def __str__(self):
return f"{self.name}"

class Candidate(models.Model):

def __str__(self):
return f"{self.id}: {self.employee} knows - {self.skill}"

class Job(models.Model):
title = models.CharField(max_length = 64)
skills = models.ManyToManyField(Skill, blank=True, related_name="Jobs")

def __str__(self):
return f"{self.title}"


In views.py, i have 'finder' function :

def finder(job_id):
job = Job.objects.get(id=job_id) # get the specific job
relevant_candidates = [] # all the relevant candidates of this kob
common = [] # number of common skills between the employee_skill and the
relevant_employees_by_title = Employee.objects.filter(title = job.title) # first filter the candidates by the job title
job_skills = []
for skill in job.skills.all():
print(skill.id)
job_skills.append(skill.id)

for employee in relevant_employees_by_title:
employee_skills =[]
candidateCorrect = Candidate.objects.filter(employee__id = employee.id).values_list('skill', flat=True)
for skill in candidateCorrect:
employee_skills.append(skill)

common_skills = list(set(job_skills) & set(employee_skills))

if (len(common_skills)>0): #if there are common skills
relevant_candidates.append(employee)
common.append(len(common_skills))

candidates = zip(relevant_candidates,common)
candidates = sorted(candidates,key = lambda t: t[1], reverse = True) # sort the candidates by the number of common skiils , descending order
candidates = candidates[:50] # Select the best 50 candidates

return candidates


This function get the job_id and need to find the best candidates for this job : first by matching between the job title to the employee title (for ex' : software developer), and then matching between candidate's skills to job's required skiils .

I think that my function is inefficient. Someone has any idea how to write it in efficient way?

You could use comprehensions to greater effect (here: directly build job_skills using a set comprehension) and also let got of having to put everything into a list.

You could also store your suitable candidates in a collections.Counter, to get the most_common(n) method for free.

from collections import Counter

def finder(job_id, n=50):
job_skills = {skill.id for skill in Job.objects.get(id=job_id).skills.all()}

candidates = Counter()
for employee in Employee.objects.filter(title=job.title):
employee_skills = Candidate.objects\
.filter(employee__id=employee.id)\
.values_list('skill', flat=True)
common_skills = len(job_skills.intersection(employee_skills))
if common_skills:
candidates[employee] = common_skills
return candidates.most_common(n)


I also followed Python's official style-guide, PEP8, which recommends not surrounding = with spaces when using it for keyword arguments, used the fact that the number 0 is falsey, while all other numbers are truthy and made the number of candidates to return configurable (with 50 the default value).

Note that this task would have been slightly easier, if the Employee object already had the skill attached, or at least a link to the Candidate object.