Download do Termo de Uso com dados do usuário no admin

TLDR: O botão “Baixar Termo de Uso do Usuário” no admin Django renderiza o template default_terms.html como PDF via WeasyPrint, com os placeholders [USUÁRIO] e [ACEITE] substituídos pelo name e accept_terms_at do usuário.

Contexto

O admin Django exibe um botão “Baixar Termo de Uso do Usuário” no change form do CommonUser. O conteúdo do termo vive em templates/admin/accounts/user/default_terms.html e contém dois placeholders textuais — [USUÁRIO] e [ACEITE] — que devem ser substituídos pelos campos name e accept_terms_at do usuário no momento do download. O PDF é gerado on-the-fly, não é persistido.

Objetivos

  • Renderizar default_terms.html como PDF dinâmico no servidor
  • Retornar HttpResponse com Content-Type: application/pdf e Content-Disposition: attachment
  • Manter o botão existente no template (o href já aponta pra URL do admin)

Fora de escopo

  • Salvar o PDF gerado em disco ou S3
  • Versionar o termo por usuário (histórico de aceites)
  • Exibir o PDF em iframe no admin

Mudanças

pyproject.toml

  • Adicionar weasyprint às dependências (uv add weasyprint)

templates/admin/accounts/user/default_terms.html

  • Substituir o literal [USUÁRIO] (aparece no corpo do termo e no bloco de assinatura) por {{ user.name|default:"—" }}
  • Substituir [ACEITE] por {{ user.accept_terms_at|date:"d/m/Y H:i"|default:"Não informado" }}
  • Substituir (data do aceite) no bloco local-data por {{ user.accept_terms_at|date:"d/m/Y"|default:"—" }}

apps/accounts/admin.py (BaseUserAdmin)

  • Adicionar URL <int:user_id>/download-terms-pdf/ em get_urls(), nomeada accounts_user_download_terms_pdf
  • Implementar view download_terms_pdf(request, user_id):
    1. get_object_or_404(User, pk=user_id)
    2. Renderiza templates/admin/accounts/user/default_terms.html com contexto {"user": user}
    3. Converte HTML em PDF com weasyprint.HTML(string=html).write_pdf()
    4. Retorna HttpResponse(pdf, content_type="application/pdf") com header Content-Disposition: attachment; filename="termo-<user.id>.pdf"

templates/admin/accounts/user/change_form.html

  • Sem alteração (o href já usa {% url 'admin:accounts_user_download_terms_pdf' original.pk %})

Como verificar

  1. Abrir o admin em /dash/accounts/commonuser/<id>/change/
  2. Clicar em “Baixar Termo de Uso do Usuário”
  3. O PDF baixado deve conter o name do usuário nos dois pontos onde havia [USUÁRIO] e o accept_terms_at formatado onde havia [ACEITE]
  4. Usuário sem accept_terms_at deve exibir “Não informado” no bloco de assinatura e “—” no bloco de data local
  5. Layout do PDF deve preservar o CSS do template (fontes serifadas, linha de assinatura, text-align: justify)

Documentação

Nenhuma mudança em .project/docs/rules/ — o comportamento de download é um detalhe de admin, não uma regra de negócio.