Files
project-managment/src/tickets/models.py
T
sankalp 72f0474f45 feat(src/tickets): add database indexes for performance
Improve query speed on Ticket, TicketComment, and TicketPriority by indexing fields used in frequent filters and ordering.
2026-06-30 10:42:10 +05:45

207 lines
6.6 KiB
Python

import random
import string
from django.conf import settings
from django.db import models
def generate_ticket_uuid(prefix):
rand = "".join(random.choices(string.ascii_uppercase + string.digits, k=6))
return f"{prefix}-{rand}"
class TicketPriority(models.Model):
name = models.CharField(max_length=255, unique=True)
color = models.CharField(max_length=7, default="#6B7280")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "ticket_priorities"
verbose_name = "Ticket Priority"
verbose_name_plural = "Ticket Priorities"
indexes = [
models.Index(fields=["name"]),
]
def __str__(self):
return self.name
class TicketStatus(models.Model):
project = models.ForeignKey(
"projects.Project", on_delete=models.CASCADE, related_name="ticket_statuses"
)
name = models.CharField(max_length=255)
color = models.CharField(max_length=7, default="#10B981")
sort_order = models.IntegerField(default=0)
is_completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "ticket_statuses"
verbose_name = "Ticket Status"
verbose_name_plural = "Ticket Statuses"
indexes = [
models.Index(fields=["project", "sort_order"]),
models.Index(fields=["project", "is_completed"]),
models.Index(fields=["project", "name"]),
]
def __str__(self):
return f"[{self.project.ticket_prefix}] {self.name}"
class Ticket(models.Model):
project = models.ForeignKey(
"projects.Project", on_delete=models.CASCADE, related_name="tickets"
)
status = models.ForeignKey(
TicketStatus, on_delete=models.CASCADE, related_name="tickets"
)
epic = models.ForeignKey(
"epics.Epic",
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="tickets",
)
priority = models.ForeignKey(
TicketPriority,
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="tickets",
)
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
uuid = models.CharField(max_length=255, unique=True, editable=False)
start_date = models.DateField(blank=True, null=True)
due_date = models.DateField(blank=True, null=True)
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name="created_tickets",
)
assignees = models.ManyToManyField(
settings.AUTH_USER_MODEL,
through="TicketUser",
related_name="assigned_tickets",
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "tickets"
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
indexes = [
models.Index(fields=["project", "status"]),
models.Index(fields=["status", "created_at"]),
models.Index(fields=["project", "created_at"]),
models.Index(fields=["project", "updated_at"]),
models.Index(fields=["due_date"]),
models.Index(fields=["priority"]),
models.Index(fields=["created_by"]),
models.Index(fields=["epic"]),
models.Index(fields=["name"]),
models.Index(fields=["start_date"]),
models.Index(fields=["project", "name"]),
models.Index(fields=["project", "start_date", "due_date"]),
models.Index(fields=["due_date", "status"]),
]
def __str__(self):
return f"{self.uuid} - {self.name}"
def save(self, *args, **kwargs):
if not self.uuid:
self.uuid = generate_ticket_uuid(self.project.ticket_prefix)
super().save(*args, **kwargs)
class TicketUser(models.Model):
ticket = models.ForeignKey(
Ticket, on_delete=models.CASCADE, related_name="ticket_assignees"
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "ticket_users"
verbose_name = "Ticket Assignee"
verbose_name_plural = "Ticket Assignees"
constraints = [
models.UniqueConstraint(
fields=["ticket", "user"], name="unique_ticket_user"
)
]
indexes = [
models.Index(fields=["ticket", "user"]),
models.Index(fields=["user"]),
]
def __str__(self):
return f"{self.user} -> {self.ticket}"
class TicketHistory(models.Model):
ticket = models.ForeignKey(
Ticket, on_delete=models.CASCADE, related_name="histories"
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="ticket_histories",
)
status = models.ForeignKey(
TicketStatus, on_delete=models.CASCADE, related_name="histories"
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "ticket_histories"
verbose_name = "Ticket History"
verbose_name_plural = "Ticket Histories"
indexes = [
models.Index(fields=["ticket", "created_at"]),
models.Index(fields=["user", "created_at"]),
]
def __str__(self):
return f"{self.ticket.uuid} -> {self.status.name} by {self.user}"
class TicketComment(models.Model):
ticket = models.ForeignKey(
Ticket, on_delete=models.CASCADE, related_name="comments"
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="ticket_comments",
)
parent = models.ForeignKey(
"self", on_delete=models.CASCADE, null=True, blank=True, related_name="replies"
)
comment = models.TextField(help_text="Rich text HTML content")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = "ticket_comments"
verbose_name = "Ticket Comment"
verbose_name_plural = "Ticket Comments"
indexes = [
models.Index(fields=["ticket", "created_at"]),
models.Index(fields=["user"]),
]
def __str__(self):
return f"Comment by {self.user} on {self.ticket.uuid}"