Improve query speed on Ticket, TicketComment, and TicketPriority by indexing fields used in frequent filters and ordering.
207 lines
6.6 KiB
Python
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}"
|