Динамическое добавление/удаление полей DateFields в наборе форм Django
У меня очень специфическая проблема, связанная с пакетом django-bootstrap-datepicker-plus.
В моем приложении Todo list я хочу иметь возможность добавлять задачи на несколько определенных дат. У меня есть модель, есть форма, включая набор форм, и даже есть JavaScript, который обрабатывает динамическую процедуру добавления/удаления.
Проблема заключается в том, что процесс клонирования моих DateField
каким-то образом приводит в беспорядок divs DatePicker
- см. результат в последнем блоке кода ниже.
# model.py
from django.db import models
from datetime import time
# Create your models here.
class Task(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50, default="")
description = models.CharField(max_length=500, default="")
entry_date = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now=True)
specific_dates = models.ManyToManyField('SpecificDate', blank=True)
due_until = models.TimeField(auto_now_add=False, default=time(12, 0))
class SpecificDate(models.Model):
todo = models.ForeignKey(Task, on_delete=models.CASCADE)
date = models.DateField(auto_now_add=False, blank=True, null=True)
class Meta:
# ensure each specific date is unique per task
unique_together = ('todo', 'date')
# forms.py
from bootstrap_datepicker_plus.widgets import DatePickerInput, TimePickerInput
from django import forms
from .models import Task, SpecificDate
class TaskForm(forms.ModelForm):
class Meta:
model = Task
fields = [
'title',
'description',
'due_until',
]
widgets = {
'due_until': TimePickerInput(options={'stepping': 5, 'format': 'HH:mm'}),
'description': forms.Textarea({'rows': 3}),
}
class SpecificDateForm(forms.ModelForm):
class Meta:
model = SpecificDate
fields = ['date']
widgets = {
'date': DatePickerInput(),
}
SpecificDateFormset = forms.inlineformset_factory(
Task, SpecificDate,
form=SpecificDateForm,
fields=('date',),
extra=1,
can_delete=True
)
<!-- task_form.html -->
{% extends "task/base.html" %}
{% load crispy_forms_tags %}
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New entry</legend>
{% if form.non_field_errors %}
<div class="alert alert-danger">
{{ form.non_field_errors }}
</div>
{% endif %}
{% crispy form %}
<div id="formset-container">
{{ formset.management_form }}
{% for form in formset %}
{% if form.errors %}
<div class="alert alert-danger">
{{ form.errors }}
</div>
{% endif %}
<div id="formset-date" class="formset-date d-flex align-items-center">
<div class="flex-grow-1 mr-2">
{{ form.date|as_crispy_field }}
</div>
<div>
<button type="button" class="btn btn-sm btn-danger remove-date" name="remove-date">-</button>
<button type="button" class="btn btn-sm btn-success add-date" name="add-date">+</button>
</div>
</div>
{% endfor %}
</div>
</fieldset>
<div class="form-group">
<button class="btn btn-primary" type="submit" name="add_new">Save</button>
<a class="btn btn-warning" href="{% url 'task-new' %}">Restart</a>
</div>
</form>
{{ form.media }}
</div>
{% endblock content %}
HTML-сниппет с набором форм после нажатия кнопки 'add' выглядит следующим образом:
Как вы можете видеть (если посмотрите очень внимательно), свойство dataset.name в DatePicker не обновляется. Точнее, оно обновляется - element.dataset.name
имеет правильное имя во время обработки - но в отрисованном HTML оно возвращается к первоначальному имени, и я также получаю эти <input type="hidden" name="null" value="">
элементы.
Вопрос простой: Как я могу получить правильные имена наборов данных в соответствующих полях <input>
, чтобы POST
запрос при отправке содержал правильные элементы?
Потребовалось несколько итераций, но в итоге я получил рабочий JavaScript-код для решения своей проблемы. Он также позволяет отключить все кнопки добавления/удаления, кроме последней. Это не очень красиво, но работает.