-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfields.py
More file actions
131 lines (110 loc) · 5.15 KB
/
fields.py
File metadata and controls
131 lines (110 loc) · 5.15 KB
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
131
from urllib.parse import urlparse
from rest_framework import serializers
from partner_programs.models import PartnerProgramField
class PartnerProgramFieldValueUpdateSerializer(serializers.Serializer):
field_id = serializers.PrimaryKeyRelatedField(
queryset=PartnerProgramField.objects.all(),
source="field",
)
value_text = serializers.CharField(
required=False,
allow_blank=True,
allow_null=True,
help_text="Укажите значение для поля.",
)
def validate(self, attrs):
field = attrs.get("field")
value_text = attrs.get("value_text")
validator = self._get_validator(field)
validator(field, value_text, attrs)
return attrs
def _get_validator(self, field: PartnerProgramField):
validators = {
"text": self._validate_text,
"textarea": self._validate_text,
"checkbox": self._validate_checkbox,
"select": self._validate_select,
"radio": self._validate_radio,
"file": self._validate_file,
}
try:
return validators[field.field_type]
except KeyError:
raise serializers.ValidationError(
f"Тип поля '{field.field_type}' не поддерживается."
)
def _validate_text(self, field: PartnerProgramField, value, attrs):
if field.is_required:
if value is None or str(value).strip() == "":
raise serializers.ValidationError(
"Поле должно содержать текстовое значение."
)
else:
if value is not None and not isinstance(value, str):
raise serializers.ValidationError("Ожидается строка для текстового поля.")
def _validate_checkbox(self, field: PartnerProgramField, value, attrs):
if field.is_required and value in (None, ""):
raise serializers.ValidationError(
"Значение обязательно для поля типа 'checkbox'."
)
if value is not None:
if isinstance(value, bool):
attrs["value_text"] = "true" if value else "false"
elif isinstance(value, str):
normalized = value.strip().lower()
if normalized not in ("true", "false"):
raise serializers.ValidationError(
"Для поля типа 'checkbox' ожидается 'true' или 'false'."
)
attrs["value_text"] = normalized
else:
raise serializers.ValidationError(
"Неверный тип значения для поля 'checkbox'."
)
def _validate_select(self, field: PartnerProgramField, value, attrs):
self._validate_choice_field(field, value, "select")
def _validate_radio(self, field: PartnerProgramField, value, attrs):
self._validate_choice_field(field, value, "radio")
def _validate_choice_field(self, field: PartnerProgramField, value, field_type):
options = field.get_options_list()
if not options:
raise serializers.ValidationError(
f"Для поля типа '{field_type}' не заданы допустимые значения."
)
if field.is_required:
if value is None or value == "":
raise serializers.ValidationError(
f"Значение обязательно для поля типа '{field_type}'."
)
else:
if value is None or value == "":
return
if value is not None:
if not isinstance(value, str):
raise serializers.ValidationError(
f"Ожидается строковое значение для поля типа '{field_type}'."
)
if value not in options:
raise serializers.ValidationError(
f"Недопустимое значение для поля типа '{field_type}'. "
f"Ожидается одно из: {options}."
)
def _validate_file(self, field: PartnerProgramField, value, attrs):
if field.is_required:
if value is None or value == "":
raise serializers.ValidationError("Файл обязателен для этого поля.")
if value is not None:
if not isinstance(value, str):
raise serializers.ValidationError(
"Ожидается строковое значение для поля 'file'."
)
if not self._is_valid_url(value):
raise serializers.ValidationError(
"Ожидается корректная ссылка (URL) на файл."
)
def _is_valid_url(self, url: str) -> bool:
try:
parsed = urlparse(url)
return parsed.scheme in ("http", "https") and bool(parsed.netloc)
except Exception:
return False