Files
neuf-www/dnscms/images/models.py
T
ponas cff6376129
dnscms / ci (push) Successful in 1m10s
web / ci (push) Successful in 2m38s
dnscms: version image URLs by file hash so media can be cached as immutable
2026-10-15 01:43:10 +02:00

81 lines
2.8 KiB
Python

from django.db import models
from django.utils.html import mark_safe
from django.utils.translation import gettext_lazy as _
from grapple.models import (
GraphQLString,
)
from grapple.utils import get_media_item_url
from wagtail.images.models import AbstractImage, AbstractRendition, Image
from wagtail.search import index
class CustomImage(AbstractImage):
alt = models.CharField(
max_length=512,
blank=True,
verbose_name="Alternativ tekst",
help_text=(
"Er ikke synlig på nettsiden, men leses opp for de som bruker skjermlesere. "
"Viktig for SEO og tilgjengelighet. "
"Beskriv det du ser i bildet som til en blind person. "
'F.eks. "Portrettbilde av Jahn Teigen" eller '
'"To personer på en scene som skyter på hverandre med luftpistoler"'
),
)
attribution = models.CharField(
max_length=255,
blank=True,
verbose_name="Kreditering",
help_text=mark_safe(
"<em>Foto:</em> eller <em>Illustrasjon: </em> etterfulgt av "
"navn på fotograf, illustratør, organisasjon, eller liknende."
),
)
admin_form_fields = Image.admin_form_fields + ("alt", "attribution")
@property
def default_alt_text(self):
return self.alt or self.title
class Meta(AbstractImage.Meta):
verbose_name = _("image")
verbose_name_plural = _("images")
permissions = [
("choose_image", "Can choose image"),
]
@property
def versioned_url(self):
# Original files keep their upload name, so deleting an image and
# uploading another with the same name reuses the URL. The content hash
# makes the URL change with the file, which lets the media proxy and
# Next's image optimizer cache it as immutable.
url = get_media_item_url(self)
if not self.file_hash:
return url
return f"{url}?v={self.file_hash[:8]}"
graphql_fields = [
# Replaces Grapple's own `url` field and resolver
GraphQLString("url", source="versioned_url", required=True),
GraphQLString("alt"),
GraphQLString("attribution"),
]
# Wagtail indexes title, description and tags. Editors describe the picture
# in `alt` rather than in `description`, so it is boosted alongside title.
search_fields = AbstractImage.search_fields + [
index.SearchField("alt", boost=10),
index.AutocompleteField("alt"),
index.SearchField("attribution"),
index.AutocompleteField("attribution"),
]
class Rendition(AbstractRendition):
image = models.ForeignKey(CustomImage, on_delete=models.CASCADE, related_name="renditions")
class Meta:
unique_together = (("image", "filter_spec", "focal_point_key"),)