Move tag slug logic onto Tag.slug @property

Replaces the tag_filename_safe() helper with a Tag.slug property
that returns the slugified form via django.utils.text.slugify.
Call sites now just use tag.slug directly.
This commit is contained in:
Claude 2026-04-21 17:32:25 +00:00
parent 0041a2d407
commit 2ea66d05d1
No known key found for this signature in database
4 changed files with 10 additions and 15 deletions

View File

@ -36,7 +36,6 @@ from archivebox.core.tag_utils import (
normalize_has_snapshots_filter,
normalize_tag_sort,
rename_tag as rename_tag_record,
tag_filename_safe,
)
from archivebox.crawls.models import Crawl
from archivebox.api.v1_crawls import CrawlSchema
@ -725,7 +724,7 @@ def tag_urls_export(request: HttpRequest, tag_id: int):
raise HttpError(404, "Tag not found") from err
response = HttpResponse(export_tag_urls(tag), content_type="text/plain; charset=utf-8")
response["Content-Disposition"] = f'attachment; filename="tag-{tag_filename_safe(tag.name)}-urls.txt"'
response["Content-Disposition"] = f'attachment; filename="tag-{tag.slug}-urls.txt"'
return response
@ -737,7 +736,7 @@ def tag_snapshots_export(request: HttpRequest, tag_id: int):
raise HttpError(404, "Tag not found") from err
response = HttpResponse(export_tag_snapshots_jsonl(tag), content_type="application/x-ndjson; charset=utf-8")
response["Content-Disposition"] = f'attachment; filename="tag-{tag_filename_safe(tag.name)}-snapshots.jsonl"'
response["Content-Disposition"] = f'attachment; filename="tag-{tag.slug}-snapshots.jsonl"'
return response

View File

@ -15,6 +15,7 @@ from statemachine import State, registry
from django.db import models
from django.db.models import QuerySet
from django.utils.functional import cached_property
from django.utils.text import slugify
from django.utils import timezone
from django.core.cache import cache
from django.urls import reverse_lazy
@ -69,6 +70,11 @@ class Tag(ModelWithUUID):
def __str__(self):
return self.name
@property
def slug(self) -> str:
"""ASCII-safe slugified form of the tag name (derived, not stored)."""
return slugify(self.name or "") or "tag"
@property
def api_url(self) -> str:
return str(reverse_lazy("api-1:get_tag", args=[self.id]))

View File

@ -10,7 +10,6 @@ from django.db.models import Count, F, QuerySet
from django.db.models.functions import Lower
from django.http import HttpRequest
from django.urls import reverse
from django.utils.text import slugify
from archivebox.core.host_utils import build_snapshot_url, build_web_url
from archivebox.core.models import Snapshot, SnapshotTag, Tag
@ -36,11 +35,6 @@ def normalize_tag_name(name: str) -> str:
return (name or "").strip()
def tag_filename_safe(name: str) -> str:
"""ASCII-safe filename fragment for a tag name (via django.utils.text.slugify)."""
return slugify(name or "") or "tag"
def normalize_tag_sort(sort: str = "created_desc") -> str:
valid_sorts = {key for key, _label in TAG_SORT_CHOICES}
return sort if sort in valid_sorts else "created_desc"

View File

@ -179,11 +179,9 @@ def test_tag_snapshots_export_returns_jsonl(client, api_token, tagged_data):
HTTP_HOST=ADMIN_HOST,
)
from archivebox.core.tag_utils import tag_filename_safe
assert response.status_code == 200
assert response["Content-Type"].startswith("application/x-ndjson")
assert f"tag-{tag_filename_safe(tag.name)}-snapshots.jsonl" in response["Content-Disposition"]
assert f"tag-{tag.slug}-snapshots.jsonl" in response["Content-Disposition"]
body = response.content.decode()
assert '"type": "Snapshot"' in body
assert '"tags": "Alpha Research"' in body
@ -198,10 +196,8 @@ def test_tag_urls_export_returns_plain_text_urls(client, api_token, tagged_data)
HTTP_HOST=ADMIN_HOST,
)
from archivebox.core.tag_utils import tag_filename_safe
assert response.status_code == 200
assert response["Content-Type"].startswith("text/plain")
assert f"tag-{tag_filename_safe(tag.name)}-urls.txt" in response["Content-Disposition"]
assert f"tag-{tag.slug}-urls.txt" in response["Content-Disposition"]
exported_urls = set(filter(None, response.content.decode().splitlines()))
assert exported_urls == {snapshot.url for snapshot in snapshots}