HTMX-Как получить валидную форму, когда поле "keyup changed"

У меня есть forms.py следующего вида. Я использую htmx для валидации. И я хотел бы получить всю форму для использования функции form.is_valid(). Но в моем случае я не получаю валидной формы.

Есть ли способ получить всю форму с помощью HTMX?

forms.py

class UniversityForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.form_id = 'university-form'
        self.helper.attrs = {
            'hx-post': reverse_lazy('index'),
            'hx-target': '#university-form',
            'hx-swap': 'outerHTML'
        }
        self.helper.add_input(Submit('submit', 'Submit'))
    
    subject = forms.ChoiceField(
        choices=User.Subjects.choices,
        widget=forms.Select(attrs={
            'hx-get': reverse_lazy('check-subject'),
            'hx-target': '#div_id_subject',
            'hx-trigger': 'change'
        })
    )
    date_of_birth = forms.DateField(widget=forms.DateInput(attrs={'type': 'date', 'max': datetime.now().date()}))

    class Meta:
        model = User
        fields = ('username', 'password', 'date_of_birth', 'subject')
        widgets = {
            'password': forms.PasswordInput(),
            'username': forms.TextInput(attrs={
                'hx-get': reverse_lazy('check-username'),
                'hx-target': '#div_id_username',
                'hx-trigger': 'keyup[target.value.length > 3]'
            })
        }

    def clean_username(self):
        username = self.cleaned_data['username']
        if len(username) <= 3:
            raise forms.ValidationError("Username is too short")
        return username

    def clean_subject(self):
        subject = self.cleaned_data['subject']
        if User.objects.filter(subject=subject).count() > 3:
            raise forms.ValidationError("There are no spaces on this course")
        return subject


    def save(self, commit=True):
        """ Hash user's password on save """
        user = super().save(commit=False)
        user.set_password(self.cleaned_data['password'])
        if commit:
            user.save()
        return user

views.py

def check_username(request):
    form = UniversityForm(request.GET)
    
    if form.is_valid():
        print('Valid')
    else:
        print('No Valid')
        print(form.errors)
        print(form['date_of_birth'])
    context = {
        'field': as_crispy_field(form['username']),
        'valid': not form['username'].errors
    }
    return render(request, 'partials/field.html', context)

Ошибка: Даже все поля заполнены; мой вывод >print('No Valid') >print(form.errors) >print(form['date_of_birth']) следующие...

No Valid
<ul class="errorlist"><li>password<ul class="errorlist"><li>This field is required.</li></ul></li><li>date_of_birth<ul class="errorlist"><li>This field is required.</li></ul></li><li>subject<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
<input type="date" name="date_of_birth" max="2022-03-15" required id="id_date_of_birth">

Проверка имени пользователя HTMX GET запроса активируется только на поле username. По умолчанию HTMX не включает в запрос никакой другой родительский элемент, что и является причиной сообщения об ошибке отсутствия полей.

Для включения других элементов в запрос можно использовать атрибут hx-include, в котором перечисляется CSS-селектор запроса дополнительных полей:

class Meta:
    model = User
    fields = ('username', 'password', 'date_of_birth', 'subject')
    widgets = {
        'password': forms.PasswordInput(),
        'username': forms.TextInput(attrs={
            'hx-get': reverse_lazy('check-username'),
            'hx-target': '#div_id_username',
            'hx-trigger': 'keyup[target.value.length > 3]',
            'hx-include': '[name="password",name="date_of_birth",name="subject"]'
        })
    }

Примечание: в POST-запросе вам не нужно использовать это, потому что вы поместили атрибут HTMX на самый внешний элемент формы, поэтому по умолчанию HTMX будет включать каждое поле (дочерние элементы формы) в запрос.

Вернуться на верх