Files
teacher_site/consultations/forms.py
T
prog1764 bab18e8129 fix: SECRET_KEY/DEBUG из env, валидаторы паролей, django-axes, обязательное consent (PRJ-5)
- SECRET_KEY: только из env (DJANGO_SECRET_KEY), без дефолта приложение не стартует
- DEBUG: только DJANGO_DEBUG=1; ALLOWED_HOSTS из env
- AUTH_PASSWORD_VALIDATORS: стандартные 4 валидатора (мин. длина 8)
- django-axes: подключён (бэкенд, middleware, лимит 5 попыток, кулдаун 1ч)
- consent_given: обязательное согласие на обработку ПД в форме
2026-08-04 19:51:16 +04:00

82 lines
3.3 KiB
Python

from django import forms
from django.utils import timezone
from .models import ConsultationRequest, ConsultationSlot
class AvailableSlotChoiceField(forms.ModelChoiceField):
def label_from_instance(self, slot):
local_start = timezone.localtime(slot.start_at)
return (
f"{local_start:%d.%m.%Y} в {local_start:%H:%M} "
f{slot.duration_minutes} минут · {slot.get_format_display()}"
)
class ConsultationRequestForm(forms.ModelForm):
slot = AvailableSlotChoiceField(
queryset=ConsultationSlot.objects.none(),
empty_label="Выберите свободное время",
label="Удобное время",
)
class Meta:
model = ConsultationRequest
fields = (
"name",
"phone",
"contact",
"student_grade",
"subject",
"exam",
"format",
"slot",
"comment",
"consent_given",
)
widgets = {
"name": forms.TextInput(attrs={"placeholder": "Как к вам обращаться"}),
"phone": forms.TelInput(attrs={"placeholder": "+7 (999) 123-45-67"}),
"contact": forms.TextInput(attrs={"placeholder": "@username, WhatsApp и т. п."}),
"comment": forms.Textarea(
attrs={
"placeholder": "Класс, темы и вопросы, которые хотите разобрать",
"rows": 4,
}
),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["slot"].queryset = ConsultationSlot.objects.available()
for name, field in self.fields.items():
if name != "consent_given":
field.widget.attrs["class"] = "form-control"
self.fields["consent_given"].widget.attrs["class"] = "consent-control"
self.fields["contact"].required = False
self.fields["student_grade"].required = False
self.fields["comment"].required = False
def clean_slot(self):
slot = self.cleaned_data["slot"]
if not slot.is_available:
raise forms.ValidationError("Это время уже занято. Выберите другой свободный слот.")
return slot
def clean(self):
cleaned_data = super().clean()
slot = cleaned_data.get("slot")
subject = cleaned_data.get("subject")
requested_format = cleaned_data.get("format")
if slot and subject and slot.subject not in (ConsultationSlot.Subject.ANY, subject):
self.add_error("slot", "Это время доступно только для другого предмета.")
if slot and requested_format not in (ConsultationRequest.Format.ANY, slot.format):
self.add_error("format", f"Для выбранного времени доступен формат: {slot.get_format_display()}.")
return cleaned_data
def clean_consent_given(self):
consent = self.cleaned_data.get("consent_given")
if not consent:
raise forms.ValidationError("Необходимо согласие на обработку персональных данных.")
return consent