
Feature: Question Bookmarks & Activity History - Open Past Paper
Easily save questions and track previously solved ones with the new Bookmarks and Last Viewed features.


Feature: Question Bookmarks & Activity History - Open Past Paper
Easily save questions and track previously solved ones with the new Bookmarks and Last Viewed features.


Folder Table and many the 1:Many relationship from User to Folder and then the similarly a M:M relationship with the Questions table. An empty migration in Django is a migration file that does not automatically detect any model changes, but is still created so we can manually add database operations or custom logic.
Uncategorized.Folder TableSaved Question TableUncategorized folder during user creation:
Uncategorized Folder.Uncategorized for every existing user and then updates all the Saved question to belong to that Uncategorized folder.class Folder(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, related_name="question_folders", on_delete=models.CASCADE ) name = models.CharField(max_length=100, null=False) color = models.CharField(max_length=100, null=False) is_default = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('user', 'name') ordering = ['-is_default', 'name'] # Default folder first, then alphabetical def __str__(self): return f"{self.user.username} - {self.name}" # prevent deleting the default folder def delete(self, *args, **kwargs): if self.is_default: raise ValueError("Cannot delete the default folder") super().delete(*args, **kwargs) @classmethod def get_or_create_default(cls, user): """Get or create the default 'Uncategorized' folder for a user.""" folder, created = cls.objects.get_or_create( user=user, is_default=True, defaults={'name': 'Uncategorized', 'color': '#808080'} # Add default color ) return folder
class SavedQuestion(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="user_saved_questions", on_delete=models.CASCADE) question = models.ForeignKey(Question, related_name="saved_question", on_delete=models.CASCADE) folder = models.ForeignKey( Folder, related_name="saved_questions", on_delete=models.CASCADE, null=True, # Temporarily nullable for migration blank=True ) saved_at = models.DateTimeField(auto_now=True) class Meta: unique_together = ('user', 'question') def save(self, *args, **kwargs): if not self.folder: self.folder = Folder.get_or_create_default(self.user) super().save(*args, **kwargs)
@receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_default_folder(sender, instance, created, **kwargs): if created: from pastpaper.models import Folder Folder.objects.create( user=instance, name='Uncategorized', is_default=True )
python manage.py makemigrations pastpaper
# 0018_folder_savedquestion_folder.py # Generated by Django 5.0.2 on 2026-02-06 05:24 import django.db.models.deletion from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ("pastpaper", "0017_alter_savedquestion_saved_at_and_more"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name="Folder", fields=[ ( "id", models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=100)), ("color", models.CharField(max_length=100)), ("is_default", models.BooleanField(default=False)), ("created_at", models.DateTimeField(auto_now_add=True)), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="question_folders", to=settings.AUTH_USER_MODEL, ), ), ], options={ "ordering": ["-is_default", "name"], "unique_together": {("user", "name")}, }, ), migrations.AddField( model_name="savedquestion", name="folder", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="saved_questions", to="pastpaper.folder", ), ), ]
python manage.py makemigrations pastpaper --empty --name populate_default_folders
# Generated by Django 5.0.2 on 2026-02-06 05:24 from django.db import migrations class Migration(migrations.Migration): # our previous migrations file dependencies = [ ("pastpaper", "0018_folder_savedquestion_folder"), ] operations = []
# Generated by Django 5.0.2 on 2026-02-06 05:24 from django.db import migrations def create_default_folders(apps, schema_editor): Folder = apps.get_model('pastpaper', 'Folder') SavedQuestion = apps.get_model('pastpaper', 'SavedQuestion') User = apps.get_model('authentication', 'User') # Adjust app name if different for user in User.objects.all(): # Create default folder for each user folder, _ = Folder.objects.get_or_create( user_id=user.id, is_default=True, defaults={'name': 'Uncategorized'} ) for saved in SavedQuestion.objects.filter(folder__isnull=True): folder = Folder.objects.get(user_id=saved.user_id, is_default=True) saved.folder = folder saved.save() class Migration(migrations.Migration): dependencies = [ ("pastpaper", "0018_folder_savedquestion_folder"), ] operations = [ migrations.RunPython(create_default_folders), ]
python manage.py migrate pastpaper