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):
    employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name="employee")
    skill = models.ForeignKey(Skill, on_delete=models.CASCADE, related_name="skill")

    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():

    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:

        common_skills = list(set(job_skills) & set(employee_skills))
        if (len(common_skills)>0): #if there are 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\
                                   .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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.