/
poi_category_translation_form.py
130 lines (105 loc) · 4.51 KB
/
poi_category_translation_form.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from django.core.exceptions import ValidationError
from django.forms import inlineformset_factory
from django.forms.formsets import DELETION_FIELD_NAME
from django.forms.models import BaseInlineFormSet
from django.utils.translation import gettext_lazy as _
if TYPE_CHECKING:
from typing import Any
from ...models import Language, POICategory, POICategoryTranslation
from ..custom_model_form import CustomModelForm
logger = logging.getLogger(__name__)
class POICategoryTranslationForm(CustomModelForm):
"""
Form for creating and modifying POI category translation objects
"""
def __init__(self, **kwargs: Any) -> None:
r"""
Initialize POI category translation form
:param \**kwargs: The supplied keyword arguments
"""
# Instantiate CustomModelForm
super().__init__(**kwargs)
# Do not require category and name fields
self.fields["category"].required = False
self.fields["name"].required = False
# Set custom language labels
language_name = self.instance.language.translated_name
self.fields["name"].widget.attrs.update(
{"placeholder": _("Enter name in {} here").format(language_name)}
)
self.fields["name"].label = _("Translation in {}").format(language_name)
def clean(self) -> dict[str, Any]:
"""
This method extends the ``clean()``-method to delete translations with an empty name.
:return: The cleaned data (see :ref:`overriding-modelform-clean-method`)
"""
cleaned_data = super().clean()
# If the name field is empty, delete the form
if not cleaned_data.get("name") and "name" not in self.errors:
cleaned_data[DELETION_FIELD_NAME] = True
return cleaned_data
class Meta:
"""
This class contains additional meta configuration of the form class, see the :class:`django.forms.ModelForm`
for more information.
"""
#: The model of this :class:`django.forms.ModelForm`
model = POICategoryTranslation
#: The fields of the model which should be handled by this form
fields = ["category", "language", "name"]
class BaseInlinePOICategoryTranslationFormSet(BaseInlineFormSet):
"""
A formset for translations of POI categories
"""
def get_form_kwargs(self, index: int) -> dict[str, dict[str, Language]]:
"""
Return additional keyword arguments for each individual formset form.
(see :meth:`~django.views.generic.edit.ModelFormMixin.get_form_kwargs` and
:ref:`django:custom-formset-form-kwargs`)
:param index: The index of the initialized form
(will be ``None`` if the form being constructed is a new empty form)
:return: The form kwargs
"""
kwargs = super().get_form_kwargs(index)
# Only add the additional instances for extra forms which do not have the initial data
if index >= self.initial_form_count():
# Get the relative index of all extra forms
rel_index = index - self.initial_form_count()
# Get all remaining languages
languages = Language.objects.all()
if self.instance.id:
languages = Language.objects.exclude(
id__in=self.instance.translations.values_list(
"language__id", flat=True
)
)
# Assign the language to the form with this index
kwargs["additional_instance_attributes"] = {
"language": languages[rel_index]
}
return kwargs
def clean(self) -> None:
"""
Make sure that at least one translation is given
:raises ~django.core.exceptions.ValidationError: When not a single form contains a valid text
"""
super().clean()
if not any(form.cleaned_data.get("name") for form in self):
raise ValidationError(_("At least one translation is required."))
def poi_category_translation_formset_factory() -> type:
"""
Build the formset class
:returns: The POICategoryTranslationFormset class
"""
num_languages = Language.objects.count()
return inlineformset_factory(
parent_model=POICategory,
model=POICategoryTranslation,
form=POICategoryTranslationForm,
formset=BaseInlinePOICategoryTranslationFormSet,
min_num=num_languages,
max_num=num_languages,
)