在Django模板中显示未知数量的字段,并将另一条记录的字段内容作为标签

时间:2017-10-17 14:04:07

标签: python django django-forms django-templates

我有一个Django应用程序,我希望能够在多个实例中使用。一个模型(列表)可以具有可变数量的字段(针对不同的实例),但是将始终具有该实例的那些额外字段。我想通过管理员添加这些额外的字段,所以我创建了这样的模型:

class BespokeField (models.Model):
    name = models.CharField(
        max_length = 20,
        verbose_name = "Field Title"
    )

    def __unicode__(self):
        return self.name

class Listing (models.Model):
    name = models.CharField (
        verbose_name = 'Listing',
        max_length = 30
    )
    slug = models.SlugField (
        verbose_name = "Slug",
        allow_unicode = True,
        unique=True,
        blank=True,
        null=True
    )

class ListingBespokeField (models.Model):
    bespoke_field = models.ForeignKey(BespokeField)
    listing = models.ForeignKey(Listing)
    value = models.CharField (
        max_length = 60
    )

    def __unicode__(self):
        return u'%s | %s' % (self.listing.name, self.bespoke_field.name)

理论是admin指定定制字段,然后以表格形式显示给用户。在管理员中这是相对简单的,因为我可以假设用户的智能,所以我的admin.py看起来像:

class ListingBespokeFieldInline(admin.TabularInline):
    model = ListingBespokeField
    extra = len(BespokeField.objects.all())
    max_num = len(BespokeField.objects.all())

class ListingAdmin(admin.ModelAdmin):
    inlines = [ListingBespokeFieldInline]

这确实意味着管理员用户必须从下拉列表中选择每个BespokeField中的一个,但我对此并不感到不舒服,因为通过使用unique_together确保每个都只有一个。

我无法解决的问题是以友好的方式向非管理员用户提供此信息。我想要的是BespokeField.name在表单上显示为ListingBespokeField.value的标签。

这就是我在forms.py中的内容(对于ListingBespokeField)。

class ListingBespokeFieldInline(forms.ModelForm):
    class Meta:
        model = ListingBespokeField
        exclude =['id']
        widgets = {
            'bespoke_field' : forms.HiddenInput(),
            'value' : forms.TextInput(attrs={'class' : 'form-control'})
        }

class ListingBespokeFieldForm(forms.ModelForm):
    class Meta:
        model = ListingBespokeField
        exclude = ()

BESPOKE_FIELD_COUNT = len(BespokeField.objects.all())

ListingBespokeFieldInlineFormSet = forms.inlineformset_factory (
    Listing,
    ListingBespokeField,
    form=ListingBespokeFieldInline,
    extra = BESPOKE_FIELD_COUNT,
    max_num = BESPOKE_FIELD_COUNT,
    exclude = ['id'],
    can_delete=False,
    can_order=False
)

然后我试图通过模板呈现它如下:

<table class="table">
    {{ bespokefields.management_form }}

    {% for form in bespokefields.forms %}
        {% if forloop.first %}
        <thead>
            <tr>
                {% for field in form.visible_fields %}
                    <th>{{ field.label|capfirst }}</th>
                {% endfor %}
            </tr>
        </thead>
        {% endif %}
        <tr class="formset_row bespokefield">
            <td>
                {{ form.listing }}{{ form.id }}{{ form.bespoke_field }}
                {{ form.bespoke_field.label }}
            </td>
            <td>{{ form.value }}</td>
        </tr>
    {% endfor %}
</table>

这不起作用。我可以使用一些见解。

1 个答案:

答案 0 :(得分:2)

这是我的解决方案:

<table class="table">
    {{ bespokefields.management_form }}

    {% for form in bespokefields.forms %}
        <tr class="formset_row bespokefield">
            <td>
                {{ form.listing }}{{ form.id }}
                <select id="id_listingbespokefield_set-{{ forloop.counter0 }}-bespoke_field" name="listingbespokefield_set-{{ forloop.counter0 }}-bespoke_field" class="form-control">
                {% with forloop.counter as counter %}
                    {% for x,y in form.fields.bespoke_field.choices %}
                        {% if counter == forloop.counter0 %}
                            <option value="{{x}}" selected>{{y}}</option>
                        {% endif %}
                    {% endfor %}
                {% endwith %}
                </select>
            </td>
            <td>{{ form.value }}</td>
        </tr>
    {% endfor %}
</table>