已解决:如何在 Django 中的表单错误中重新显示带有选定值的 formset 和 Select2 字段

Resolved: How to re-display formset & Select2 field with selected value on form error in Django

在搜索了几天并尝试了不同的选项之后,我决定最终 post 问题。

我有一个模板,其中包含一个表单和 2 个不同的表单集。

其中一个表单集使用带有 GenericForeignKey 的中间模型,该模型将引用另外两个模型。 对于表单集,我正在使用内联表单集并添加一个 CharField,它与 Select2 一起使用以进行 ajax 调用以检查其他两个模型。 ajax 调用的值 return 将是一个 json/dict 和 3 key/value 对。

我遇到的问题是,当提交模板时出现错误,如何在再次显示模板时重新显示在 Select2 CharField 中输入的值?

该值在 self.data 中并被发送回模板。 但是,到目前为止我所尝试的一切都不会重新显示带有先前选择的值或已提交的值的 select2 字段。

提交的值已 return 以 json/dict、key/value 格式编入模板 form.fieldname.value,但我不确定如何使用它来重新填充 select2 字段。

感谢任何建议或链接。如果有其他设置方法,我很想听听。

谢谢。

更新:2021-03-18

希望所有这些都是来自各种文件的相关位。

models.py

class SiteDomain(models.Model):
    website = models.ForeignKey(
        WebSite,
        on_delete=models.CASCADE,
    )
    domain_model = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        help_text=(
            "The model that the website entry is related to. eg: Domain or SubDomain"
        ),
    )
    object_id = models.PositiveIntegerField(
        help_text="The ID of the model object the entry is related to."
    )
    content_object = GenericForeignKey("domain_model", "object_id")
    content_object.short_description = "Domain Name:"

views.py

class AddWebsite(View):
    def get(self, request, *args, **kwargs):

        domain_formset = inlineformset_factory(
            WebSite,
            SiteDomain,
            formset=SiteDomainInlineFormSet,
            fields=(),
            extra=3,
        )

forms.py

class SiteDomainInlineFormSet(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        self.account = kwargs.pop('account', None)
        super(SiteDomainInlineFormSet, self).__init__(*args, **kwargs)

    def add_fields(self, form, index):
        super().add_fields(form, index)

        form.fields["domain_name"] = forms.CharField(
            max_length=255,
            widget=forms.Select(),
            required=False,
        )

模板

<script type="text/javascript">
function s2search() {
    $('.domain-lookup-ajax').select2({
        width: 'style',
        ajax: {
            url: "{% url 'accounts_ajax:website_domain_lookup' %}",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                var query = {
                    term: params.term,
                    acct_id: '{{ account.id }}',
                }
                return query;
            },
            processResults: function (data, params) {
                return {
                    results: data,
                };
            },
            cache: true
        },
        placeholder: 'Enter at least 2 characters for search.',
        minimumInputLength: 2,
    });
}
</script>

<form action="" method="post">
    {% csrf_token %}

    {{ domain_formset.management_form }}
    {{ app_formset.management_form }}

        {% for form in domain_formset %}
            <div class="domainfieldWrapper" id="row_{{ forloop.counter0 }}">
                <select id="id_dform-{{ forloop.counter0 }}-domain_name" class="domain_name domain-lookup-ajax" name="dform-{{ forloop.counter0 }}-domain_name"></select>

                <button id="id_dform-{{ forloop.counter0 }}-button" class="button" type="button" onclick="clearSelect('id_dform-{{ forloop.counter0 }}-domain_name')">Clear</button>
            </div>
        {% endfor %}

</form>

ajax 调用将 return 类似于:

{"model_id":"74", "domain_id":"177", "name":"alfa.first-example.com"}

旁注: 我还测试了第二个表单集中的 select2 字段,如果存在任何表单错误,则在重新加载模板时也不会重新填充它。这是我所期望的,因为它基本上使用相同的设置,除了由 ajax 调用编辑的值 return 用于正常的 ModelChoiceField。

结合使用 https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2、js 和 Django 模板标签,我得到了适合我的东西。