在 Django 模板中自定义内联表单集选择

Customizing inlineformset choice in Django template

我有一些要自定义的表格。

我手动呈现字段 - 一切正常,直到到达特定字段(它本身是一个 InlineFormset)。我正在尝试自定义这些选项,但似乎不知道该怎么做。

我的 forms.py 看起来像这样:

class SummativeScoreForm(forms.ModelForm):
    subdomain_proficiency_level = forms.ModelChoiceField(
        empty_label="Undecided",
        queryset=SubdomainProficiencyLevel.objects.none(),
        widget=forms.RadioSelect,
        required=False,
    )

    def __init__(self, request, *args, **kwargs):
        super(SummativeScoreForm, self).__init__(*args, **kwargs)
        if self.instance:
            if request.user == self.instance.summative.employee:
                self.fields["subdomain_proficiency_level"].disabled = True
        self.fields[
            "subdomain_proficiency_level"
        ].queryset = SubdomainProficiencyLevel.objects.filter(
            subdomain=self.instance.subdomain
        )
        self.fields[
            "subdomain_proficiency_level"
        ].label = f"""
        {self.instance.subdomain.character_code}:
        {self.instance.subdomain.short_description}
        """

    class Meta:
        model = SummativeScore
        fields = "__all__"


SummativeScoreInlineFormset = inlineformset_factory(
    Summative,
    SummativeScore,
    fields=("subdomain_proficiency_level",),
    can_delete=False,
    extra=0,
    form=SummativeScoreForm,
)

我的 summative_score_form 模板如下所示:

            <form method="post" novalidate>
                {% csrf_token %}
                    {% include "myapp/includes/summative_score_response_formset_snippet.html" with formset=form %}
                <button type="submit" class="btn btn-primary"><i class="fal fa-clipboard-check"></i> Submit Updated Scores</button>
            </form>

summative_score_response_formset_snippet 看起来像这样:

{{ formset.management_form }}
{% for formset_form in formset.forms %}
    {% if formset_form.non_field_errors %}
        <ul>
            {% for error in formset_form.non_field_errors %}
                <li>{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}

    {% for hidden_field in formset_form.hidden_fields %}
        {% if hidden_field.errors %}
            <ul>
                {% for error in hidden_field.errors %}
                    <li>
                        (Hidden field {{ hidden_field.name }}) {{ error }}
                    </li>
                {% endfor %}
            </ul>
        {% endif %}

        {{ hidden_field }}

    {% endfor %}
    {% for field in formset_form.visible_fields %}
        {% if field.name == 'subdomain_proficiency_level' %}
            <label class="form-check-label" for="{{ field.id_for_label }}">
                {{ field.label }}
            </label>
            <ul id="{{ field.auto_id }}" class="form-check mt-2">
                {% for choice in formset_form.subdomain_proficiency_level %}
                    <div class="form-check">
                        <!--
                        THIS IS THE PART I WOULD LIKE TO CUSTOMIZE:
                        Unsatisfactory (name) Lorum Ipsum (description)
                        Satisfactory (name) Lorum Ipsum (description)
                        Excellent (name) Lorum Ipsum (description)
                        CURRENTLY IT ONLY SHOWS THE NAME
                         -->
                        {{ choice }}
                    </div>
                {% endfor %}
            </ul>
            {% if field.help_text %}
                <p class="help">{{ field.help_text|safe }}</p>
            {% endif %}
        {% else %}
            {{ field }}
        {% endif %}
    {% endfor %}
{% endfor %}

我的模型是这样的:

class SubdomainProficiencyLevel(CreateUpdateMixin):
    "THIS IS THE 'UNSATISFACTORY' (name) 'LORUM IPSUM' (description)"
    name = models.CharField(max_length=75)
    description = models.TextField()
    sequence = models.IntegerField()

    class Meta:
        ordering = ["sequence"]
        verbose_name = "Subdomain Rank"
        verbose_name_plural = "Subdomain Ranks"

    def __str__(self):
        """
        THIS IS WHAT IS 'CHOICE' IN THE FORM
        I'm trying to edit this to add styles to the self.description on the form
        """
        return f"{self.name}"

class SummativeScore(CreateUpdateMixin, CreateUpdateUserMixin):
    summative = models.ForeignKey(Summative, on_delete=models.PROTECT)
    subdomain = models.ForeignKey(Subdomain, on_delete=models.PROTECT)
    subdomain_proficiency_level = models.ForeignKey(
        SubdomainProficiencyLevel,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
    )

    class Meta:
        ordering = ["subdomain__character_code"]
        verbose_name = "SummativeScore"
        verbose_name_plural = "SummativeScores"

    def __str__(self):
        """Unicode representation of SummativeScore."""
        return f"{self.subdomain_proficiency_level}"

该视图基于 Class FormView

class SummativeScoreFormView(
    LoginRequiredMixin,
    UserIsObserverOrObserveeMixin,
    SingleObjectMixin,
    FormView,
):

    model = Summative
    template_name = "myapp/summative_score_form.html"
    pk_url_kwarg = "summative_id"

    def get(self, request, *args, **kwargs):
        summative_id = kwargs.pop("summative_id")
        self.object = self.get_object(
            queryset=Summative.objects.filter(id=summative_id)
        )
        return super().get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        summative_id = kwargs.pop("summative_id")
        self.object = self.get_object(
            queryset=Summative.objects.filter(id=summative_id)
        )
        return super().post(request, *args, **kwargs)

    def get_form(self, form_class=None):
        formset = SummativeScoreInlineFormset(
            **self.get_form_kwargs(), instance=self.object
        )
        return formset

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs["form_kwargs"] = {"request": self.request}
        return kwargs

    def form_valid(self, form):
        form.save()
        messages.success(self.request, "Changes were saved!")
        return super().form_valid(form)

    def form_invalid(self, form):
        return super().form_invalid(form)

    def get_success_url(self):
        user_id = self.kwargs["user_id"]
        summative_id = self.kwargs["summative_id"]
        return reverse(
            "myapp:summative_detail",
            kwargs={
                "user_id": user_id,
                "summative_id": summative_id,
            },
        )

如您在模板中所见 - 我使用模板变量 {{ choice }}

渲染 SubdomainProficiencyLevel 对象

我试过 {{ choice.description }}{{ choice.name }} <span class="bold">{{ choice.description }}</span> 但没有任何显示。

我也尝试过调整模型上的 __str__ 方法 - 那里的更改有效,但不会呈现为 HTML(就像预期的字符串一样)。

在 HTML 中自定义它的最佳方法是什么?

我最终创建了一个自定义单选按钮 class(类似于 the documentation

class CustomRadioSelect(forms.RadioSelect):
    def create_option(
        self, name, value, label, selected, index, subindex=None, attrs=None
    ):
        option = super().create_option(
            name, value, label, selected, index, subindex, attrs
        )
        if value:
            option["attrs"]["description"] = value.instance.description
        return option

以以下形式使用:

    subdomain_proficiency_level = forms.ModelChoiceField(
        empty_label="Undecided",
        queryset=SubdomainProficiencyLevel.objects.none(),
        widget=CustomRadioSelect(),
        required=False,
    )

然后我可以在模板中像这样访问它:

{{ choice.data.attrs.description }}