7

I'm trying to add custom fields to an InlineFormset using the following code, but the fields won't show up in the Django Admin. Is the InlineFormset too locked down to allow this? My print "ding" test fires as expected, I can print out the form.fields and see them all there, but the actual fields are never rendered in the admin.

admin.py

from django.contrib import admin
import models
from django.forms.models import BaseInlineFormSet
from django import forms
from forms import ProgressForm
from django.template.defaultfilters import slugify

class ProgressInlineFormset(BaseInlineFormSet):
    def add_fields(self, form, index):
        print "ding"
        super(ProgressInlineFormset, self).add_fields(form, index)
        for criterion in models.Criterion.objects.all():
            form.fields[slugify(criterion.name)] = forms.IntegerField(label=criterion.name)

class ProgressInline(admin.TabularInline):
    model = models.Progress
    extra = 8
    formset = ProgressInlineFormset

class ReportAdmin(admin.ModelAdmin):
    list_display = ("name", "pdf_column",)
    search_fields = ["name",]
    inlines = (ProgressInline,)

admin.site.register(models.Report, ReportAdmin)

3 Answers 3

6

I did it another way:

forms.py:

from django import forms
class ItemAddForm(forms.ModelForm):
    my_new_field = forms.IntegerField(initial=1, label='quantity')
    class Meta:
        model = Item

admin.py:

from django.contrib import admin
from forms import *
class ItemAddInline(admin.TabularInline):
    form = ItemAddForm
    fields = (..., 'my_new_field')

This works so far, I only need to override somehow the save method to handle this new field. See this: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#form . It says that by default Inlines use BaseModelForm, which is send to formset_factory. It doesn't work for me, tried to subclass BaseModelForm with errors (no attribute '_meta'). So I use ModelForm instead.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for this answer. Do you have any more information regarding what you did to override save for the Inline Formset?
Want to mention, that label= part is very important. Without it there is error AttributeError: Unable to lookup 'my_new_field'
for the save part, only need to override the save method in ItemAddForm. Calling the super().save(comit=False) first then finishing the change yourself
2

You can do it by another way (Dynamic forms):

admin.py

class ProgressInline(admin.TabularInline):
    model = models.Progress
    extra = 8

    def get_formset(self, request, obj=None, **kwargs):
        extra_fields = {'my_field': forms.CharField()}
        kwargs['form'] = type('ProgressForm', (forms.ModelForm,), extra_fields)
        return super(ProgressInline, self).get_formset(request, obj, **kwargs)

3 Comments

Good example, but does not work in 1.10.2. From @alekwisnia's example I found, that without label= new_field does not work. How\where to add the label in your example? Thanks.
@TitanFighter if you mean the custom field label you can try with something like extra_fields = {'my_field': forms.CharField(label='My label')}
yeh... avoid that and just create a real ModelForm class
0
model = models.Progress

In the admin there will be only the fields defined in this Progress model. You have no fields/fieldsets option overwriting it.

If you want to add the new ones, there are two options:

  • In the model definition, add those new additional fields (make them optional!)
  • In the admin model (admin.TabularInline), add something something like:

    fields = ('newfield1', 'newfield2', 'newfield3')

Take a look at fields, fieldsets.

1 Comment

Not what I was hoping to hear, but oh well. At least its confirmed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.