title: Django: Dynamically update ModelForm's Field widgets
body: <p>I want to dynamically generate ModelForm's Meta Class widgets according to <code>exercise_type</code> field from <code>Exercise</code> class.
  How can I get the value?</p>
  <pre><code>class ExerciseAdminForm(ModelForm):
          
      class Meta:
          model = Exercise
          fields = '__all__'
          widgets = {
              'starter_code': _make_language_mode(exercise_type=Exercise.exercise_type)
          }
  </code></pre>
  <hr />
  <p><strong>I don't know how to get the excercise_object.</strong></p>
  <hr />
  <p>Basically I need to override the default form in the administration interface, to use <a href="https://codemirror.net" rel="nofollow noreferrer">CodeMirror</a> and <a href="http://www.skulpt.org" rel="nofollow noreferrer">Skulpt</a> support for entry fields.</p>
  <pre><code>class ExerciseAdminForm(ModelForm):
      
      def __init__(self, *args, **kwargs):
          super(ExerciseAdminForm, self).__init__(*args, **kwargs)
          print(&quot;DEBUG: len(kwargs)=&quot;,len(kwargs))
          initial_dict = kwargs['initial']
          print(&quot;DEBUG: len(initial_dict)=&quot;,len(initial_dict))
          self.fields['starter_code'].widget = _make_language_mode(exercise_type=excercise_object.exercise_type)
  
  
      class Meta:
          model = Exercise
          fields = '__all__'
          widgets = {
              'preamble': _make_markdown_mode()
          }
  </code></pre>
  <p>My debug message shows:</p>
  <blockquote>
  <p>('DEBUG: len(kwargs)=', 1)</p>
  <p>('DEBUG: len(initial_dict)=', 0)</p>
  </blockquote>
  <p>My function get called from the Python 2.7 library site-packages:</p>
  <blockquote>
  <p>/root/.virtualenvs/codebench/local/lib/python2.7/site-packages/django/contrib/admin/options.py</p>
  </blockquote>
  <p>At line 1481:</p>
  <pre><code>form = ModelForm(initial=initial) 
  </code></pre>
  <p>In the changeform_view function:</p>
  <pre><code>@csrf_protect_m
  @transaction.atomic
  def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
  
      to_field = request.POST.get(TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR))
      if to_field and not self.to_field_allowed(request, to_field):
          raise DisallowedModelAdminToField(&quot;The field %s cannot be referenced.&quot; % to_field)
  
      model = self.model
      opts = model._meta
      add = object_id is None
  
      if add:
          if not self.has_add_permission(request):
              raise PermissionDenied
          obj = None
  
      else:
          obj = self.get_object(request, unquote(object_id), to_field)
  
          if not self.has_change_permission(request, obj):
              raise PermissionDenied
  
          if obj is None:
              raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {
                  'name': force_text(opts.verbose_name), 'key': escape(object_id)})
  
          if request.method == 'POST' and &quot;_saveasnew&quot; in request.POST:
              return self.add_view(request, form_url=reverse('admin:%s_%s_add' % (
                  opts.app_label, opts.model_name),
                  current_app=self.admin_site.name))
  
      ModelForm = self.get_form(request, obj)
      if request.method == 'POST':
          form = ModelForm(request.POST, request.FILES, instance=obj)
          if form.is_valid():
              form_validated = True
              new_object = self.save_form(request, form, change=not add)
          else:
              form_validated = False
              new_object = form.instance
          formsets, inline_instances = self._create_formsets(request, new_object, change=not add)
          if all_valid(formsets) and form_validated:
              self.save_model(request, new_object, form, not add)
              self.save_related(request, form, formsets, not add)
              if add:
                  self.log_addition(request, new_object)
                  return self.response_add(request, new_object)
              else:
                  change_message = self.construct_change_message(request, form, formsets)
                  self.log_change(request, new_object, change_message)
                  return self.response_change(request, new_object)
      else:
          if add:
              initial = self.get_changeform_initial_data(request)
              form = ModelForm(initial=initial)
              formsets, inline_instances = self._create_formsets(request, self.model(), change=False)
          else:
              form = ModelForm(instance=obj)
              formsets, inline_instances = self._create_formsets(request, obj, change=True)
  
      adminForm = helpers.AdminForm(
          form,
          list(self.get_fieldsets(request, obj)),
          self.get_prepopulated_fields(request, obj),
          self.get_readonly_fields(request, obj),
          model_admin=self)
      media = self.media + adminForm.media
  
      inline_formsets = self.get_inline_formsets(request, formsets, inline_instances, obj)
      for inline_formset in inline_formsets:
          media = media + inline_formset.media
  
      context = dict(self.admin_site.each_context(request),
          title=(_('Add %s') if add else _('Change %s')) % force_text(opts.verbose_name),
          adminform=adminForm,
          object_id=object_id,
          original=obj,
          is_popup=(IS_POPUP_VAR in request.POST or
                    IS_POPUP_VAR in request.GET),
          to_field=to_field,
          media=media,
          inline_admin_formsets=inline_formsets,
          errors=helpers.AdminErrorList(form, formsets),
          preserved_filters=self.get_preserved_filters(request),
      )
  
      context.update(extra_context or {})
  
      return self.render_change_form(request, context, add=add, change=not add, obj=obj, form_url=form_url)
  </code></pre>