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

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING, Any 

4 

5from django import forms 

6from django.utils.translation import gettext_lazy as _ 

7 

8from mesh.model.file_helpers import DELETE_FILE_PREFIX, file_exists 

9 

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 

12 

13 

14class FileInput(forms.FileInput): 

15 """ 

16 Custom file widget. 

17 Simply overrides the default template and adds data to the context for rendering. 

18 """ 

19 

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 

26 

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) 

41 

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 ) 

53 

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 

65 

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 ) 

70 

71 return context