167 lines
6.6 KiB
Python
167 lines
6.6 KiB
Python
from django.db import models
|
|
from django.utils.text import slugify
|
|
from django.core.validators import FileExtensionValidator
|
|
|
|
|
|
class JobPosition(models.Model):
|
|
"""Model for job positions/openings"""
|
|
|
|
EMPLOYMENT_TYPE_CHOICES = [
|
|
('full-time', 'Full Time'),
|
|
('part-time', 'Part Time'),
|
|
('contract', 'Contract'),
|
|
('internship', 'Internship'),
|
|
('remote', 'Remote'),
|
|
]
|
|
|
|
LOCATION_TYPE_CHOICES = [
|
|
('remote', 'Remote'),
|
|
('on-site', 'On-site'),
|
|
('hybrid', 'Hybrid'),
|
|
]
|
|
|
|
STATUS_CHOICES = [
|
|
('active', 'Active'),
|
|
('closed', 'Closed'),
|
|
('draft', 'Draft'),
|
|
]
|
|
|
|
# Basic Information
|
|
title = models.CharField(max_length=255, help_text="Job title")
|
|
slug = models.SlugField(max_length=255, unique=True, blank=True)
|
|
department = models.CharField(max_length=100, blank=True, help_text="Department or category")
|
|
|
|
# Employment Details
|
|
employment_type = models.CharField(
|
|
max_length=20,
|
|
choices=EMPLOYMENT_TYPE_CHOICES,
|
|
default='full-time'
|
|
)
|
|
location_type = models.CharField(
|
|
max_length=20,
|
|
choices=LOCATION_TYPE_CHOICES,
|
|
default='remote'
|
|
)
|
|
location = models.CharField(max_length=255, default='Remote', help_text="Work location")
|
|
|
|
# Position Details
|
|
open_positions = models.PositiveIntegerField(default=1, help_text="Number of open positions")
|
|
experience_required = models.CharField(max_length=100, blank=True, help_text="e.g., 3+ years")
|
|
|
|
# Salary Information
|
|
salary_min = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
|
|
salary_max = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
|
|
salary_currency = models.CharField(max_length=10, default='USD')
|
|
salary_period = models.CharField(max_length=20, default='per month', help_text="e.g., per month, per year")
|
|
salary_additional = models.TextField(blank=True, help_text="Additional salary info like bonuses, benefits")
|
|
|
|
# Job Description
|
|
short_description = models.TextField(blank=True, help_text="Brief description for listing page")
|
|
about_role = models.TextField(blank=True, help_text="About this role / Who we are")
|
|
requirements = models.JSONField(default=list, blank=True, help_text="List of requirements")
|
|
responsibilities = models.JSONField(default=list, blank=True, help_text="List of responsibilities")
|
|
qualifications = models.JSONField(default=list, blank=True, help_text="List of qualifications")
|
|
bonus_points = models.JSONField(default=list, blank=True, help_text="Nice to have skills")
|
|
benefits = models.JSONField(default=list, blank=True, help_text="What you get")
|
|
|
|
# Dates and Status
|
|
start_date = models.CharField(max_length=100, default='ASAP', help_text="Expected start date")
|
|
posted_date = models.DateTimeField(auto_now_add=True)
|
|
updated_date = models.DateTimeField(auto_now=True)
|
|
deadline = models.DateTimeField(null=True, blank=True, help_text="Application deadline")
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
|
|
|
|
# SEO and Metadata
|
|
featured = models.BooleanField(default=False, help_text="Feature this job on homepage")
|
|
priority = models.IntegerField(default=0, help_text="Higher number = higher priority in listing")
|
|
|
|
class Meta:
|
|
ordering = ['-priority', '-posted_date']
|
|
verbose_name = 'Job Position'
|
|
verbose_name_plural = 'Job Positions'
|
|
|
|
def __str__(self):
|
|
return f"{self.title} ({self.open_positions} positions)"
|
|
|
|
def save(self, *args, **kwargs):
|
|
if not self.slug:
|
|
self.slug = slugify(self.title)
|
|
# Ensure unique slug
|
|
original_slug = self.slug
|
|
counter = 1
|
|
while JobPosition.objects.filter(slug=self.slug).exists():
|
|
self.slug = f"{original_slug}-{counter}"
|
|
counter += 1
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
class JobApplication(models.Model):
|
|
"""Model for job applications"""
|
|
|
|
STATUS_CHOICES = [
|
|
('new', 'New'),
|
|
('reviewing', 'Reviewing'),
|
|
('shortlisted', 'Shortlisted'),
|
|
('interviewed', 'Interviewed'),
|
|
('accepted', 'Accepted'),
|
|
('rejected', 'Rejected'),
|
|
]
|
|
|
|
# Related Job
|
|
job = models.ForeignKey(JobPosition, on_delete=models.CASCADE, related_name='applications')
|
|
|
|
# Applicant Information
|
|
first_name = models.CharField(max_length=100)
|
|
last_name = models.CharField(max_length=100)
|
|
email = models.EmailField()
|
|
phone = models.CharField(max_length=20, blank=True)
|
|
|
|
# Professional Information
|
|
current_position = models.CharField(max_length=255, blank=True, help_text="Current job title")
|
|
current_company = models.CharField(max_length=255, blank=True)
|
|
years_of_experience = models.CharField(max_length=50, blank=True)
|
|
|
|
# Application Details
|
|
cover_letter = models.TextField(blank=True, help_text="Cover letter or message")
|
|
resume = models.FileField(
|
|
upload_to='career/resumes/%Y/%m/',
|
|
validators=[FileExtensionValidator(allowed_extensions=['pdf', 'doc', 'docx'])],
|
|
help_text="Upload your resume (PDF, DOC, DOCX)"
|
|
)
|
|
portfolio_url = models.URLField(blank=True, help_text="Link to portfolio or LinkedIn")
|
|
|
|
# Additional Information
|
|
linkedin_url = models.URLField(blank=True)
|
|
github_url = models.URLField(blank=True)
|
|
website_url = models.URLField(blank=True)
|
|
|
|
# Availability
|
|
available_from = models.DateField(null=True, blank=True, help_text="When can you start?")
|
|
notice_period = models.CharField(max_length=100, blank=True, help_text="Notice period if applicable")
|
|
|
|
# Salary Expectations
|
|
expected_salary = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
|
|
salary_currency = models.CharField(max_length=10, default='USD')
|
|
|
|
# Application Metadata
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='new')
|
|
applied_date = models.DateTimeField(auto_now_add=True)
|
|
updated_date = models.DateTimeField(auto_now=True)
|
|
notes = models.TextField(blank=True, help_text="Internal notes (not visible to applicant)")
|
|
|
|
# Privacy
|
|
consent = models.BooleanField(default=False, help_text="Consent to data processing")
|
|
|
|
class Meta:
|
|
ordering = ['-applied_date']
|
|
verbose_name = 'Job Application'
|
|
verbose_name_plural = 'Job Applications'
|
|
|
|
def __str__(self):
|
|
return f"{self.first_name} {self.last_name} - {self.job.title}"
|
|
|
|
@property
|
|
def full_name(self):
|
|
return f"{self.first_name} {self.last_name}"
|
|
|