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}"