Django

Obrazki OG w
Django

Sygnał post_save, transaction.on_commit, adres zapisany przez update().

Gdzie to wpiąć

Strony w Django zwykle rysują karty OG ręcznie w Pillow, piksel po pikselu. Z szablonem w HTML i CSS zmieniasz wygląd w arkuszu stylów, a po stronie Pythona zostaje jedno żądanie po zapisaniu wpisu.

blog/signals.py

import requests
from django.conf import settings
from django.db import transaction
from django.db.models.signals import post_save
from django.dispatch import receiver

from .models import Post

API_URL = "https://imageapi.dev/v1/images?wait=true"


def generate_og_image(post_id: int) -> None:
    post = Post.objects.select_related("author").get(pk=post_id)
    response = requests.post(
        API_URL,
        headers={"Authorization": f"Bearer {settings.IMAGE_API_KEY}"},
        json={
            "template": "blog-og",
            "modifications": {
                "title": post.title,
                "author": post.author.get_full_name(),
                "date": post.published_at.date().isoformat(),
                "site": "yourblog.com",
            },
        },
        timeout=20,
    )
    response.raise_for_status()
    # .update() instead of .save(): it does not fire post_save again.
    Post.objects.filter(pk=post_id).update(og_image_url=response.json()["url"])


@receiver(post_save, sender=Post)
def on_post_saved(sender, instance, update_fields=None, **kwargs):
    if not instance.is_published:
        return
    # Run after the transaction commits; with Celery, call .delay() here instead.
    transaction.on_commit(lambda: generate_og_image(instance.pk))
Pułapka

Zapisuj adres przez `QuerySet.update()`, nie `post.save()`. `save()` w obsłudze `post_save` odpala sygnał ponownie — i dostajesz pętlę, która renderuje ten sam obrazek, aż coś przekroczy limit czasu.

Co dostajesz w odpowiedzi

Z ?wait=true czekasz na gotowy obrazek w tym samym połączeniu — zwykle około sekundy.

{
    "id": "img_01m08s3ez1zcv28h335g9923bw",
    "status": "completed",
    "url": "https://cdn.imageapi.dev/renders/img_01m08s3ez1zcv28h335g9923bw.png",
    "duration_ms": 912
}

Ile to kosztuje

Sto obrazków miesięcznie za darmo, potem $9 za dwa tysiące. Ten sam wpis wyrenderowany drugi raz zwraca istniejący adres i nie zużywa limitu — więc przebudowanie strony nic nie kosztuje.

Inne frameworki