From 363ba52442f978a24f2c971fa518ed982c8afdd2 Mon Sep 17 00:00:00 2001 From: Kalin Dimitrov Date: Sat, 4 Oct 2025 11:00:54 +0300 Subject: [PATCH] feat: add indexes to DB models for easier search queries --- ...03_alter_airesponse_created_at_and_more.py | 89 +++++++++++++++++++ cv/models.py | 62 ++++++------- 2 files changed, 116 insertions(+), 35 deletions(-) create mode 100644 cv/migrations/0003_alter_airesponse_created_at_and_more.py diff --git a/cv/migrations/0003_alter_airesponse_created_at_and_more.py b/cv/migrations/0003_alter_airesponse_created_at_and_more.py new file mode 100644 index 0000000..9b56fb4 --- /dev/null +++ b/cv/migrations/0003_alter_airesponse_created_at_and_more.py @@ -0,0 +1,89 @@ +# Generated by Django 5.2.7 on 2025-10-04 08:00 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cv', '0002_alter_airesponse_questionnaire'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name='airesponse', + name='created_at', + field=models.DateTimeField(auto_now_add=True, db_index=True), + ), + migrations.AlterField( + model_name='airesponse', + name='response_text', + field=models.TextField(help_text='ai generated response text'), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='application_timeline', + field=models.CharField(choices=[('immediate', 'Immediate'), ('1-3 months', '1-3 months'), ('3-6 months', '3-6 months'), ('6+ months', '6+ months')], db_index=True, max_length=20), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='company_size', + field=models.CharField(choices=[('startup', 'Startup'), ('small', 'Small'), ('medium', 'Medium'), ('enterprise', 'Enterprise')], db_index=True, max_length=10), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='experience_level', + field=models.CharField(choices=[('0-2', '0-2 years'), ('3-5', '3-5 years'), ('6+', '6+ years')], db_index=True, max_length=10), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='industry', + field=models.CharField(db_index=True, help_text='industry (max 255 characters)', max_length=255), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='job_description', + field=models.TextField(blank=True, help_text='job description (max 5000 characters)', null=True), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='location', + field=models.CharField(blank=True, help_text='location (max 255 characters)', max_length=255, null=True), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='position', + field=models.CharField(db_index=True, help_text='job position (max 255 characters)', max_length=255), + ), + migrations.AlterField( + model_name='cvquestionnaire', + name='submitted_at', + field=models.DateTimeField(auto_now_add=True, db_index=True), + ), + migrations.AddIndex( + model_name='airesponse', + index=models.Index(fields=['questionnaire', 'created_at'], name='ai_quest_created_idx'), + ), + migrations.AddIndex( + model_name='airesponse', + index=models.Index(fields=['created_at'], name='ai_created_at_idx'), + ), + migrations.AddIndex( + model_name='cvquestionnaire', + index=models.Index(fields=['user', 'submitted_at'], name='cv_user_submitted_idx'), + ), + migrations.AddIndex( + model_name='cvquestionnaire', + index=models.Index(fields=['position', 'industry'], name='cv_position_industry_idx'), + ), + migrations.AddIndex( + model_name='cvquestionnaire', + index=models.Index(fields=['experience_level', 'company_size'], name='cv_exp_company_idx'), + ), + migrations.AddIndex( + model_name='cvquestionnaire', + index=models.Index(fields=['submitted_at'], name='cv_submitted_at_idx'), + ), + ] diff --git a/cv/models.py b/cv/models.py index b132258..029f18c 100644 --- a/cv/models.py +++ b/cv/models.py @@ -26,32 +26,25 @@ class CVQuestionnaire(models.Model): ('6+ months', '6+ months'), ] - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='questionnaires') - position = models.CharField( - max_length=255, - help_text="job position (max 255 characters)" - ) - industry = models.CharField( - max_length=255, - help_text="industry (max 255 characters)" - ) - experience_level = models.CharField(max_length=10, choices=EXPERIENCE_LEVEL_CHOICES) - company_size = models.CharField(max_length=10, choices=COMPANY_SIZE_CHOICES) - location = models.CharField( - max_length=255, - blank=True, - null=True, - help_text="location (max 255 characters)" - ) - application_timeline = models.CharField(max_length=20, choices=APPLICATION_TIMELINE_CHOICES) - job_description = models.TextField( - blank=True, - null=True, - help_text="job description (max 5000 characters)" - ) - submitted_at = models.DateTimeField(auto_now_add=True) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='questionnaires', db_index=True) + position = models.CharField(max_length=255, help_text="job position (max 255 characters)", db_index=True) + industry = models.CharField(max_length=255, help_text="industry (max 255 characters)", db_index=True) + experience_level = models.CharField(max_length=10, choices=EXPERIENCE_LEVEL_CHOICES, db_index=True) + company_size = models.CharField(max_length=10, choices=COMPANY_SIZE_CHOICES, db_index=True) + location = models.CharField(max_length=255, blank=True, null=True, help_text="location (max 255 characters)") + application_timeline = models.CharField(max_length=20, choices=APPLICATION_TIMELINE_CHOICES, db_index=True) + job_description = models.TextField(blank=True, null=True, help_text="job description (max 5000 characters)") + submitted_at = models.DateTimeField(auto_now_add=True, db_index=True) resume = models.FileField(upload_to='resumes/', blank=True, null=True) + class Meta: + indexes = [ + models.Index(fields=['user', 'submitted_at'], name='cv_user_submitted_idx'), + models.Index(fields=['position', 'industry'], name='cv_position_industry_idx'), + models.Index(fields=['experience_level', 'company_size'], name='cv_exp_company_idx'), + models.Index(fields=['submitted_at'], name='cv_submitted_at_idx'), + ] + def clean(self): """ validate model data at the model level @@ -83,16 +76,15 @@ def __str__(self): class AIResponse(models.Model): - # model was OneToOneField - questionnaire = models.ForeignKey( - CVQuestionnaire, - related_name='ai_response', - on_delete=models.CASCADE - ) - response_text = models.TextField( - help_text="ai generated response text" - ) - created_at = models.DateTimeField(auto_now_add=True) + questionnaire = models.ForeignKey(CVQuestionnaire, related_name='ai_response', on_delete=models.CASCADE, db_index=True) + response_text = models.TextField(help_text="ai generated response text") + created_at = models.DateTimeField(auto_now_add=True, db_index=True) + + class Meta: + indexes = [ + models.Index(fields=['questionnaire', 'created_at'], name='ai_quest_created_idx'), + models.Index(fields=['created_at'], name='ai_created_at_idx'), + ] def clean(self): """ @@ -109,4 +101,4 @@ def __str__(self): created = self.created_at created = timezone.localtime(created).replace(microsecond=0) - return f"Response for {self.questionnaire.position} - {created.strftime('%Y-%m-%d %H:%M:%S')}" + return f"Response for {self.questionnaire.position} - {created.strftime('%Y-%m-%d %H:%M:%S')}" \ No newline at end of file