Coverage for src/mesh/views/forms/widgets.py: 42%
36 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
1from __future__ import annotations
3from typing import TYPE_CHECKING, Any
5from django import forms
6from django.utils.translation import gettext_lazy as _
8from mesh.model.file_helpers import DELETE_FILE_PREFIX, file_exists
10if TYPE_CHECKING: 10 ↛ 11line 10 didn't jump to line 11 because the condition on line 10 was never true
11 from mesh.models.file_models import BaseFileWrapperModel
14class FileInput(forms.FileInput):
15 """
16 Custom file widget.
17 Simply overrides the default template and adds data to the context for rendering.
18 """
20 # Whether multiple files are allowed.
21 allow_multiple_selected: bool
22 template_name = "mesh/forms/widgets/file.html"
23 model_class: type[BaseFileWrapperModel] | None
24 related_name: str | None
25 deletable: bool
27 def __init__(
28 self,
29 *args,
30 allow_multiple_selected: bool = False,
31 model_class: type[BaseFileWrapperModel] | None = None,
32 related_name: str | None = None,
33 deletable: bool = True,
34 **kwargs,
35 ) -> None:
36 self.allow_multiple_selected = allow_multiple_selected
37 self.model_class = model_class
38 self.related_name = related_name
39 self.deletable = deletable
40 super().__init__(*args, **kwargs)
42 def get_context(self, name: str, value, attrs) -> dict[str, Any]:
43 """
44 Add the file(s) to the context if they're all existing files.
45 """
46 context = super().get_context(name, value, attrs)
47 related_name = self.related_name or name
48 context["widget"]["delete_prefix"] = f"{DELETE_FILE_PREFIX}{related_name}"
49 context["widget"]["multiple"] = self.allow_multiple_selected
50 context["widget"]["initial_text"] = (
51 _("Choose file(s)...") if self.allow_multiple_selected else _("Choose a file...")
52 )
54 # Check the validity of the input value
55 if value:
56 check_func = file_exists
57 if self.model_class and hasattr(self.model_class, "instance_valid_file"):
58 check_func = self.model_class.instance_valid_file
59 if self.allow_multiple_selected:
60 if all([check_func(v) for v in value]):
61 context["widget"]["file_value"] = value
62 else:
63 if check_func(value):
64 context["widget"]["file_value"] = value
66 # Check whether existing files can be deleted
67 context["deletable"] = self.deletable and (
68 not self.is_required or self.allow_multiple_selected and value and len(value) > 1
69 )
71 return context