Tags: count at issue-level (model impl. only)

This commit is contained in:
Klaas van Schelven
2025-02-27 21:58:14 +01:00
parent 4404538893
commit f7e85b788c
3 changed files with 25 additions and 5 deletions

View File

@@ -1,4 +1,4 @@
# Generated by Django 4.2.19 on 2025-02-27 12:04
# Generated by Django 4.2.19 on 2025-02-27 19:46
from django.db import migrations, models
import django.db.models.deletion
@@ -9,9 +9,9 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
("events", "0019_event_storage_backend"),
("issues", "0010_issue_list_indexes"),
("projects", "0011_fill_stored_event_count"),
("events", "0019_event_storage_backend"),
]
operations = [
@@ -82,6 +82,7 @@ class Migration(migrations.Migration):
verbose_name="ID",
),
),
("count", models.PositiveIntegerField(default=0)),
(
"issue",
models.ForeignKey(

View File

@@ -18,7 +18,7 @@ https://docs.sentry.io/platforms/python/enriching-events/tags/
from django.db import models
from django.db.models import Q
from django.db.models import Q, F
from projects.models import Project
from tags.utils import deduce_tags
@@ -79,12 +79,18 @@ class IssueTag(models.Model):
value = models.ForeignKey(TagValue, blank=False, null=False, on_delete=models.CASCADE)
issue = models.ForeignKey('issues.Issue', blank=False, null=True, on_delete=models.SET_NULL, related_name='tags')
count = models.PositiveIntegerField(default=0)
class Meta:
# searching: by value, then Issue (is this so though? .qs is already on the other!)
unique_together = ('value', 'issue')
indexes = [
models.Index(fields=['issue', 'value']), # make lookups by issue (for detail pages) faster
# a point _could_ be made for ['issue', 'value' 'count'] we'll probably order by the latter in the end.
# but I suspect that in practice the sorting on by count can be done easily for a small number of items
# (and I suspect that if there are very many items, sorting is not useful, because the sparse information
# does not lead to much insight... but I might be wrong (a few tags with many values, and a long tail would
# be the counter-example))
]
@@ -156,3 +162,7 @@ def store_tags(event, issue, tags):
IssueTag.objects.bulk_create([
IssueTag(project_id=event.project_id, value=tag_value, issue=issue) for tag_value in tag_value_objects
], ignore_conflicts=True)
IssueTag.objects.filter(project_id=event.project_id, value__in=tag_value_objects, issue=issue).update(
count=F('count') + 1
)

View File

@@ -22,17 +22,19 @@ class TagsTestCase(DjangoTestCase):
self.assertEqual(self.event.tags.count(), 0)
def test_store_1_tags(self):
with self.assertNumQueries(6):
with self.assertNumQueries(7):
store_tags(self.event, self.issue, {"foo": "bar"})
self.assertEqual(self.event.tags.count(), 1)
self.assertEqual(self.issue.tags.count(), 1)
self.assertEqual(self.event.tags.first().value.value, "bar")
self.assertEqual(self.issue.tags.first().count, 1)
self.assertEqual(self.issue.tags.first().value.key.key, "foo")
def test_store_5_tags(self):
with self.assertNumQueries(6):
with self.assertNumQueries(7):
store_tags(self.event, self.issue, {f"k-{i}": f"v-{i}" for i in range(5)})
self.assertEqual(self.event.tags.count(), 5)
@@ -40,3 +42,10 @@ class TagsTestCase(DjangoTestCase):
self.assertEqual({"k-0", "k-1", "k-2", "k-3", "k-4"}, {tag.value.key.key for tag in self.event.tags.all()})
self.assertEqual({"v-0", "v-1", "v-2", "v-3", "v-4"}, {tag.value.value for tag in self.event.tags.all()})
def test_store_single_tag_twice_on_issue(self):
store_tags(self.event, self.issue, {"foo": "bar"})
store_tags(create_event(self.project, self.issue), self.issue, {"foo": "bar"})
self.assertEqual(self.issue.tags.first().count, 2)
self.assertEqual(self.issue.tags.first().value.key.key, "foo")