About Streaming HTML Documents

StreamingHttpResponse can be used not only for large audio, video, or other binary files, but also for text-based content, for example, a large HTML document of a few megabytes with data from the database.

import asyncio
import html
from asgiref.sync import sync_to_async
from django.http import StreamingHttpResponse
from .models import Trick

async def streaming_demo_html(request):
    async def generate():
        yield '''
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Streaming Tricks Demo</title>
        </head>
        <body>
            <h1>Streaming Tricks</h1>
            <p>Each trick is streamed from the database in chunks of 10.</p>
            <hr>
        '''
        await asyncio.sleep(0)  # yield control to other requests

        chunk_size = 10
        offset = 0
        count = 0

        def fetch_chunk(offset_val):
            return list(
                Trick.objects.filter(
                    publishing_status__in=(
                        Trick.PUBLISHING_STATUS_PUBLISHED,
                        Trick.PUBLISHING_STATUS_PUBLISHED_OUTDATED,
                    )
                )
                .prefetch_related("categories", "technologies")
                [offset_val:offset_val + chunk_size]
            )

        get_chunk = sync_to_async(fetch_chunk)

        while True:
            chunk = await get_chunk(offset)

            if not chunk:
                break

            for trick in chunk:
                count += 1
                safe_title = html.escape(trick.title)
                safe_url = html.escape(request.build_absolute_uri(trick.get_url_path()))

                yield f'''
            <div>
                <small>Trick #{count}</small>
                <h2><a href="{safe_url}">{safe_title}</a></h2>
            </div>
                '''
                yield " " * 1024  # padding to force browser to flush and render
                await asyncio.sleep(0.5)  # yield control between chunks

            del chunk
            offset += chunk_size

        yield f'''
            <hr>
            <p>Done! All {count} tricks streamed.</p>
        </body>
        </html>
        '''

    return StreamingHttpResponse(
        generate(),
        content_type="text/html; charset=utf-8"
    )

Tips and Tricks Programming Optimization Django 6.x Django 5.2 ASGI WSGI Uvicorn Daphne HTTP streaming