0

I need help with the following problem:

Using the Django admin, I would like to hide some fields in inline depending on whether the object exists.

Example equivalent to admin.ModelAdmin:

class ClassAdmin(admin.ModelAdmin):
    ...

    def get_form(self, request, obj=None, **kwargs):
        # if inline has not been saved
        if obj is None:
            self.fieldsets[0][1]['fields'] = tuple(x for x in self.fieldsets[0][2]['fields'] if (x!='field1'))

        else:
            self.inlines = self.inlines + [ClassInline,]

            if obj.field1 == 'N':
                self.fieldsets[2][7]['fields'] = tuple(x for x in self.fieldsets[2][8]['fields'] if (x!='field10'))

        return super(ClassAdmin, self).get_form(request, obj, **kwargs)

How can I make it equivalent to an inline?

class ClassInline(admin.StackedInline):
    # if obj:
        # display filed1, field2
    # else:
        # display filed3, field4

I tried hard and not found something to help me solve the problem. Some topics I found:

Here, Here and Here.

Can someone show an example of code that can do the job?

gustavo.sdo
  • 323
  • 1
  • 2
  • 13

2 Answers2

0

InlineModelAdmin.get_formset() is called with the current object (the current parent object I mean) as param, and builds the list of fields for the inline's form (actually for the call to inlineformset_factory()) by calling on self.get_fieldsets(), passing the current (parent) object. So overriding InlineModelAdmin.get_formset() should do:

class MyInlineAdmin(admin.StackedInline):
    def get_fieldsets(self, request, obj):
        fields = super(MyInlineAdmin, self).get_fieldsets(request, obj):
        if obj and obj.pk:
            return do_something_with(fields)
        else :
            return do_something_else_with(fields)

Now you say you "tried hard" and did "not found something" - but did you at least "tried" to just have a look at the source code ? It took me a couple minutes to figure out the call chain and args...

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • Yes @bruno-desthuilliers, First, sorry for my English, I am learning... and thanks for your answer. I read the Django source code, but I could not understand it. Your sample code, I do not quite understand how I can do to access the fields and remove them from the generation of the form ... if you compare `obj and obj.pk:` may explain why only `if obj:` not work? (this is just a curiosity). – gustavo.sdo May 14 '15 at 16:56
  • PS: I'm doing this project as college internship work, so I'm gaining many experiences ... Sorry if my question was useless :) – gustavo.sdo May 14 '15 at 16:58
  • You get the fields from the call to `super(MyInlineAdmin, self).get_fieldsets()` and return them from the method. You can do whatever you want in between... wrt/ testing `obj.pk` : I didn't check the whole code path (call stack) but the method might be called with an empty (or at least unsaved) model instance when adding, so you need to check `obj.pk` to tell if you're currently adding a new object or editing an existing one. The test on `obj` itself is to avoid a possible attribute error when trying to access `obj.pk` if `obj` happens to be `None`. – bruno desthuilliers May 17 '15 at 13:57
0

I solved the problem of a not very clean way, but it works for me. For anyone with a similar problem and need an example ... See the code below.

in admin.py

class MyInline(admin.StackedInline):
    form = MyForm
    model = MyModel
    fields = ('field1', 'field2', 'field3', 'field4', 'fied5', 'field6')
    list_display = ('field2', 'field3', 'field4', 'fied5', 'field6',)

    fieldsets = (
                (None, {
                    "fields" : ("field1",)
                }),
                ("Details", {
                    "fields" : ("field2", "field3", 'field4', 'posicao', 'venda')
                })
)


class MyAddInline(MyInline):
    """Inline displayed if there are no objects"""
    fieldsets = ((None, {
                        "fields" : ("field1",)
                }),)


class ClassXAdmin(admin.ModelAdmin):
    model = MyOtherModel
    ...

    def get_form(self, request, obj=None, **kwargs):
        if obj is None:
            ...

        else:
            status = MyModel.objects.filter(fk=obj.pk).exists()
            if status:
                self.inlines = self.inlines + [MyInline,]
            else:
                self.inlines = self.inlines + [MyAddInline,]

        return super(ClassXAdmin, self).get_form(request, obj, **kwargs)
gustavo.sdo
  • 323
  • 1
  • 2
  • 13