Как изменить GET-запрос, чтобы вызвать ответ с вложением файла (законным образом)?

У меня есть проект Django, который использует шахматный модуль python для отображения шахматной доски в главном представлении. По умолчанию это пустая доска:

views.py

import chess, chess.pgn

def index(request, pgn_slug=None):
    board = chess.Board()
    game = chess.pgn.Game.from_board(board)
    game.headers["DrawOffered"] = "False"

Главная индексная функция перехватывает AJAX-запросы и обслуживает ответы:

from django.http import JsonResponse

if request.headers.get('x-requested-with') == 'XMLHttpRequest':
    ...
    return JsonResponse(response_obj)

Или он отобразит страницу:

from django.http import HttpResponse
else:
    html = get_html(game, board)
    return HttpResponse(html)

Я хочу, чтобы один elif возвращал вложение .txt, основанное на функциях написания игры python-chess . Как мне добиться этого с хорошо сформированными запросами и ответами? Django, кажется, имеет выделенный объект ответа для такого рода вещей, но я не могу сложить два и два вместе. Возможно, что-то вроде этого?:

from django.http import FileResponse
elif request._____ == 'download': # what could mark the request?
    file_name = 'foo.txt'
    file = open(filename, 'wt')
    file.write(str(game))
    return FileResponse(file, as_attachment=True,
        filename=file_name)

Запрос запускается кнопкой на той же странице и функцией JavaScript и вызывает либо URL окна, либо URL, который динамически передается функции из AJAX:

<script>
function downloadPGN(URL) { 
    if (URL === undefined) { 
        URL = window.location.href 
    }
    // ... GET request with modified headers? 
</script>
<button type="button" id="downloadButton" 
    onClick="downloadPGN()">↓</button>

Я понимаю, что мой вопрос похож на несколько других, но все решения казались десятилетней давности и очень запутанными для того, что кажется мне довольно простой проблемой. Мне кажется, что я упускаю какую-то маленькую, жизненно важную деталь. Кто-нибудь может помочь?

Я обнаружил, что использование атрибута html download создает различные GET-заголовки. Не уверен в переносимости, но это помогло отделить запросы GET от GET с загрузкой на моей локальной системе.

fetch = request.headers.get('Sec-Fetch-Site')
dest = request.headers.get('Sec-Fetch-Dest')
if fetch == 'same-origin' and dest == 'empty':
    disp = 'attachment; filename="foo.txt"'
    return HttpResponse(get_download(game), headers={
        'Content-Disposition': disp })
else: 
    html = get_html(request.path, game, board)
    return HttpResponse(html)
Вернуться на верх