Dynamic fields in Django Admin

后端 未结 9 1464
失恋的感觉
失恋的感觉 2020-12-05 05:18

I want to have additional fields regarding value of one field. Therefor I build a custom admin form to add some new fields.

Related to the blogpost of jacobian 1 thi

9条回答
  •  自闭症患者
    2020-12-05 05:34

    The accepted answer above worked in older versions of django, and that's how I was doing it. This has now broken in later django versions (I am on 1.68 at the moment, but even that is old now).

    The reason it is now broken is because any fields within fieldsets you return from ModelAdmin.get_fieldsets() are ultimately passed as the fields=parameter to modelform_factory(), which will give you an error because the fields on your list do not exist (and will not exist until your form is instantiated and its __init__ is called).

    In order to fix this, we must override ModelAdmin.get_form() and supply a list of fields that does not include any extra fields that will be added later. The default behavior of get_form is to call get_fieldsets() for this information, and we must prevent that from happening:

    # CHOOSE ONE
    # newer versions of django use this
    from django.contrib.admin.utils import flatten_fieldsets
    # if above does not work, use this
    from django.contrib.admin.util import flatten_fieldsets
    
    class MyModelForm(ModelForm):
      def __init__(self, *args, **kwargs):
          super(MyModelForm, self).__init__(*args, **kwargs)
          # add your dynamic fields here..
          for fieldname in ('foo', 'bar', 'baz',):
              self.fields[fieldname] = form.CharField()
    
    class MyAdmin(ModelAdmin): 
       form = MyModelForm
    
        fieldsets = [
           # here you put the list of fieldsets you want displayed.. only
           # including the ones that are not dynamic
        ]
    
        def get_form(self, request, obj=None, **kwargs):
            # By passing 'fields', we prevent ModelAdmin.get_form from
            # looking up the fields itself by calling self.get_fieldsets()
            # If you do not do this you will get an error from 
            # modelform_factory complaining about non-existent fields.
    
            # use this line only for django before 1.9 (but after 1.5??)
            kwargs['fields'] =  flatten_fieldsets(self.declared_fieldsets)
            # use this line only for django 1.9 and later 
            kwargs['fields'] =  flatten_fieldsets(self.fieldsets)
    
            return super(MyAdmin, self).get_form(request, obj, **kwargs)
    
        def get_fieldsets(self, request, obj=None):
            fieldsets = super(MyAdmin, self).get_fieldsets(request, obj)
    
            newfieldsets = list(fieldsets)
            fields = ['foo', 'bar', 'baz']
            newfieldsets.append(['Dynamic Fields', { 'fields': fields }])
    
            return newfieldsets
    

提交回复
热议问题