123 lines
4.1 KiB
Python
123 lines
4.1 KiB
Python
"""Представления (views) приложения `cv`."""
|
||
|
||
from typing import Any
|
||
|
||
from django.http import FileResponse, Http404, HttpRequest
|
||
from django.views.generic.base import TemplateView, View
|
||
|
||
from cv.models import Profile
|
||
from cv.services.dowload.docx import DocxRenderer
|
||
from cv.services.dowload.pdf import PdfRenderer
|
||
|
||
|
||
class ProfileView(TemplateView):
|
||
"""Отображение профиля на главной странице."""
|
||
|
||
template_name = "index.html"
|
||
extra_context = {}
|
||
|
||
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
|
||
"""Собрать контекст для шаблона.
|
||
|
||
Args:
|
||
**kwargs: Дополнительные параметры контекста.
|
||
|
||
Returns:
|
||
dict: Словарь контекста для рендеринга шаблона.
|
||
"""
|
||
kwargs.setdefault("view", self)
|
||
extra_context = self._get_extra_context()
|
||
self.extra_context.update(extra_context)
|
||
if self.extra_context is not None:
|
||
kwargs.update(self.extra_context)
|
||
return kwargs
|
||
|
||
def _get_extra_context(self) -> dict[str, Any]:
|
||
"""Получить дополнительные данные для контекста (профиль и связанные сущности).
|
||
|
||
Returns:
|
||
dict: Дополнительные пары ключ/значение для контекста.
|
||
|
||
Raises:
|
||
Http404: Если профиль не найден.
|
||
"""
|
||
profile = Profile.objects.prefetch_related("experience", "skills_map").first()
|
||
if not profile:
|
||
raise Http404("Профиль не найден")
|
||
return {
|
||
"profile": profile,
|
||
}
|
||
|
||
|
||
class DownloadDocxView(View):
|
||
"""Скачать резюме в формате DOCX."""
|
||
|
||
_docx = DocxRenderer()
|
||
|
||
def get(self, _request: HttpRequest, *_args: Any, **_kwargs: Any) -> FileResponse:
|
||
"""Вернуть файл DOCX с содержимым резюме.
|
||
|
||
Args:
|
||
request: HTTP‑запрос.
|
||
*args: Позиционные аргументы.
|
||
**kwargs: Именованные аргументы.
|
||
|
||
Returns:
|
||
FileResponse: Ответ c приложением DOCX.
|
||
|
||
Raises:
|
||
Http404: Если профиль не найден.
|
||
"""
|
||
profile = Profile.objects.prefetch_related("experience", "skills_map").first()
|
||
if not profile:
|
||
raise Http404("Профиль не найден")
|
||
|
||
buffer = self._docx.render(profile)
|
||
|
||
safe_utf8 = f"resume_{profile.full_name.replace(' ', '_')}.docx"
|
||
buffer.seek(0)
|
||
resp = FileResponse(
|
||
buffer,
|
||
as_attachment=True,
|
||
filename=safe_utf8,
|
||
content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||
)
|
||
resp["Cache-Control"] = "no-store"
|
||
return resp
|
||
|
||
|
||
class DownloadPdfView(View):
|
||
"""Скачать резюме в формате PDF."""
|
||
|
||
_pdf = PdfRenderer()
|
||
|
||
def get(self, _request: HttpRequest, *_args: Any, **_kwargs: Any) -> FileResponse:
|
||
"""Вернуть файл PDF с содержимым резюме.
|
||
|
||
Args:
|
||
request: HTTP‑запрос.
|
||
*args: Позиционные аргументы.
|
||
**kwargs: Именованные аргументы.
|
||
|
||
Returns:
|
||
FileResponse: Ответ c приложением PDF.
|
||
|
||
Raises:
|
||
Http404: Если профиль не найден.
|
||
"""
|
||
profile = Profile.objects.prefetch_related("experience", "skills_map").first()
|
||
if not profile:
|
||
raise Http404("Профиль не найден")
|
||
|
||
stream = self._pdf.render(profile)
|
||
|
||
safe_utf8 = f"resume_{profile.full_name.replace(' ', '_')}.pdf"
|
||
resp = FileResponse(
|
||
stream,
|
||
as_attachment=True,
|
||
filename=safe_utf8,
|
||
content_type="application/pdf",
|
||
)
|
||
resp["Cache-Control"] = "no-store"
|
||
return resp
|