Виджет «Выбор даты» Tempus Dominus неправильно клонируется в Django Model Formset при использовании Dynami c Formset Library - PullRequest
2 голосов
/ 23 января 2020

У меня есть модельный набор форм, настроенный с использованием Django Dynami c Formset вместе с Хрустящими формами и библиотекой Datepicker Tempus Dominus . Это простой набор форм для пользователей, позволяющий добавлять записи строки операционных расходов - дату, категорию, описание и сумму.

Мой указатель даты работает правильно с не динамическим c формой. Однако при использовании динамических c форм и добавлении новой формы виджет в конечном итоге нацеливается на последнюю форму в наборе форм, из которой он был клонирован, а не на текущую форму (https://imgur.com/a/2GFYZ90). Вместо правильного приращения (т. Е. Form_3, form_4, form_5 и т. Д. c.), Оно просто ссылается на последнюю форму набора форм (т. Е. Form_2) перед добавлением новых. В результате, если я пытаюсь переключать средства выбора даты в любой из динамически добавляемых форм, он просто запускает тот, что находится в form_2. Обычные текстовые поля клонируются правильно без каких-либо проблем.

Как вы можете видеть в строках 19-23 opex. html, я пытаюсь реализовать функции уничтожения и повторной инициализации, как предлагалось некоторыми старыми стеками. Сообщения переполнения ( 1 , 2 и 3 ), но я нуб JS, поэтому я не уверен, что делать дальше.

models.py

class OpEx(models.Model):
    GEN_EXP = 'GE'
    OFFICE_SUP = 'OS'
    NR_EXP = 'NR'
    CATEGORY_CHOICES = [
        (GEN_EXP, 'General Expenses'),
        (OFFICE_SUP, 'Office Supplies'),
        (NR_EXP, 'Non-Recurring Expenses'),
    ]
    exp_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=0)
    exp_date = models.DateField(verbose_name='Date')
    category = models.CharField(max_length=2, choices=CATEGORY_CHOICES, default=GEN_EXP)
    description = models.CharField(max_length=255)
    amount = models.DecimalField(verbose_name='Amount ($)', max_digits=10, decimal_places=2)

forms.py

class OpExEntryForm(ModelForm):
    class Meta:
        model = OpEx
        exclude = ('id', 'exp_user')

class OpExFormSetHelper(FormHelper):
    def __init__(self, *args, **kwargs):
        super(OpExFormSetHelper, self).__init__(*args, **kwargs)
        self.form_method = 'POST'
        self.form_class = 'form-inline'
        self.form_show_labels = False
        self.layout = Layout(
            Row(
                Column('exp_date', css_class='col-sm-2'),
                Column('category', css_class='col-sm-3'),
                Column('description', css_class='col-sm-4'),
                Column(PrependedText('amount', "<span class='fa fa-dollar-sign'"), css_class='col-sm-2'),
                css_class='opex-formset-row'
            )
        )
        self.render_required_fields = True
        self.add_input(Submit('submit', 'Update operating expenses'))

views.py

def opex(request):
    OpExFormSet = modelformset_factory(OpEx, exclude=('id', 'exp_user'),
                                       widgets={'exp_date': DatePicker(attrs={'append': 'fa fa-calendar'})},
                                       form=OpExEntryForm, extra=0, can_delete=True)
    helper = OpExFormSetHelper()
    queryset = OpEx.objects.filter(exp_user=user)

    if request.method == 'POST':
        formset = OpExFormSet(request.POST, queryset=queryset)
        # Irrelevant code...
    else:
        formset = OpExFormSet(queryset=queryset)

    return render(request, 'opex.html', {'formset': formset, 'helper': helper})

opex. html

{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% load static %}
{% block extra_head %}
{{ form.media }}
{% endblock %}

{% block content %}

{% crispy formset helper %}

<!-- Load Django Dynamic Formset -->
<script type="text/javascript" src="{% static 'js/jquery.formset.js' %}"></script>
<script type="text/javascript">
$(function() {
    $('.opex-formset-row').formset({
        addText : 'add another',
        deleteText : 'remove',
        added: function (row) {
                    var datePicker = $(row).find('input[name$="exp_date"]');
                    if (datePicker.length > 0) {
                        datePicker.datetimepicker('destroy');
                    }
        }
    });
})
</script>

{% endblock %}
...