title: Django 'ModelForm' object has no attribute 'object'
body: <p>I have a ModelForm and I'm trying to display it with some of the fields disabled. In this case, <code>process_id</code>.
  The important part of my Model looks like this:</p>
  
  <h3>models.py</h3>
  
  <pre><code>class Process(models.Model):
      related_processes = models.ManyToManyField('self', blank=True, symmetrical=False)
      process_id = models.CharField(max_length=20, primary_key=True)
      normal_field = models.CharField(max_length=20)
      # a lot of fields here...
  </code></pre>
  
  <p>So basically I have a Process that can have zero or more related processes.
  This is what I have on forms.py:</p>
  
  <h3>forms.py</h3>
  
  <pre><code>class ProcessForm(ModelForm):
      class Meta:
          model = Process
          fields = '__all__'
  
  
  class EditProcessForm(ProcessForm):
      readonly_fields = ('process_id', )
  
      def __init__(self, *args, **kwargs):
          super(EditProcessForm, self).__init__(*args, **kwargs)
          for field in (field for name, field in self.fields.items() if name in self.readonly_fields):
              field.widget.attrs['disabled'] = 'true'
              field.required = False
  
      def clean(self):
          for f in self.readonly_fields:
              self.cleaned_data.pop(f, None)
          return super(EditProcessForm, self).clean()
  
  
  class NewVersionProcessForm(EditProcessForm):
      readonly_fields = ('process_id', )
  
      def __init__(self, *args, **kwargs):
          super(NewVersionProcessForm, self).__init__(*args, **kwargs)
          for field in (field for name, field in self.fields.items() if name in self.readonly_fields):
              # field.widget.attrs['disabled'] = 'true'
              # Remember this line ^
              field.required = False
  </code></pre>
  
  <p>The first time the client is filling the form, I want all fields to be editable, so I use ProcessForm. But when the client is editing the Process, I want some fields to be read-only. I found this nice solution here on stackoverflow (unfortunately I couldn't find it again) and it works perfectly when I'm editing a process.
  The difference between EditProcessForm and NewVersionProcessForm is their Views and the commented line on <code>__init__</code>.</p>
  
  <h3>views.py</h3>
  
  <pre><code>class ProcessFormView(FormView):
      template_name = 'my_app/fill_form.html'
      form_class = ProcessForm
  
      def form_valid(self, form):
          form.save()
          return redirect('my_app:show_process_page', form.cleaned_data.get('process_id'))
  
  
  class EditProcessView(UpdateView):
      model = Process
      form_class = EditProcessForm
      template_name = 'my_app/edit_form.html'
      pk_url_kwarg = 'process_id'
  
      def post(self, request, process_id):
          # This is a little hack I found here: https://stackoverflow.com/a/21262262/3773461
          # to edit an immutable QueryDict.
          mutable = request.POST._mutable
          request.POST._mutable = True
          request.POST['process_id'] = process_id
          request.POST._mutable = mutable
          return super().post(request)
  
      def form_valid(self, form):
          form.save()
          return redirect('my_app:show_process_page', self.kwargs['process_id'])
  
  class NewVersionProcessView(EditProcessView):
      template_name = 'my_app/new_version_form.html'
      form_class = NewVersionProcessForm
  
      def get(self, request, process_id):
          try:
              Process.objects.get(process_id=process_id)
              return redirect('my_app:process_already_exists_page')
          except Process.DoesNotExist:
              self.object = Process(process_id=process_id)
              last_id = self.object.get_last_version_id()
              last_process = Process.objects.get(process_id=last_id)
              last_process_dict = last_process.__dict__
              related_processes = last_process.related_processes.all()[:]
              exclude = ['_state', 'process_id']
              for key, value in last_process_dict.items():
                  if key not in exclude:
                      self.object.__dict__[key] = value
  
              # self.object.related_processes.add(*related_processes)
              # Remember this line too ^
  
              form_class = self.get_form_class()
              form = self.get_form(form_class)
              return self.form_invalid(form)
  
      def post(self, request, process_id):
          form_class = self.get_form_class()
          form = self.get_form(form_class)
          if form.is_valid():
              return self.form_valid(form)
          else:
              return self.form_invalid(form)
  
      def form_valid(self, form):
          form.save()
          return redirect('my_app:show_process_page', form.cleaned_data['process_id'])
  </code></pre>
  
  <p>The first view is a simple FormView with ProcessForm. The second view is an UpdateView. On post I just add the field that is disabled on the form (and therefore is not passed ahead normally). On form_valid I just save the form on its model (with the just added field).</p>
  
  <p>The third view is my current problem. Keep in mind that I can do 3 things with a Process: create a new one, edit it, or create a new version of an existing process. This third view intends to do the third one.
  On get, I check if I'm trying to create a process that already exists. If it doesn't, I create the Process and copy all useful data on the base process to it, except the ManyToMany field (the second "remember this line"), because I couldn't figure out a way to do that without saving the Model first.
  On post, I'm checking if the form is valid, and on form_valid, I'm saving the process.</p>
  
  <h1>What works</h1>
  
  <p>I can create and edit processes just fine. The read-only fields when editing works perfectly. The model is saved as intended.
  Also, I can create a new process using another existing process as a base (NewVersionProcessView) if the first "remember this line" is commented, that is, if all the fields are editable.</p>
  
  <h1>What doesn't work</h1>
  
  <p>If the first "remember this line" is uncommented, that is, if some of the fields are read-only, my view crashes on post. Most specifically, on form_invalid. The only thing I can think of is that somehow there's not a Process object linked to my NewVersionProcessView. I can't understand why though, because I always assign something to <code>self.object</code> on get. I cannot get the object from the database on post because it is not saved yet. Also, I cannot understand why a field being enabled or disabled affects <code>self.object</code>. Remember, the only thing that changes is that <code>field.widget.attrs['disabled'] = 'true'</code> line.
  Here is the log:</p>
  
  <pre><code>Request Method: POST
  Request URL: http://127.0.0.1:8000/my_app/new_version/999-11/
  
  Django Version: 2.0.7
  Python Version: 3.4.4
  Installed Applications:
  ['my_app.apps.MyAppConfig',
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles']
  Installed Middleware:
  ['django.middleware.security.SecurityMiddleware',
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.common.CommonMiddleware',
   'django.middleware.csrf.CsrfViewMiddleware',
   'django.contrib.auth.middleware.AuthenticationMiddleware',
   'django.contrib.messages.middleware.MessageMiddleware',
   'django.middleware.clickjacking.XFrameOptionsMiddleware']
  
  
  Traceback:
  
  File "C:\Python34\lib\site-packages\django\core\handlers\exception.py" in inner
    35.             response = get_response(request)
  
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py" in _get_response
    128.                 response = self.process_exception_by_middleware(e, request)
  
  File "C:\Python34\lib\site-packages\django\core\handlers\base.py" in _get_response
    126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)
  
  File "C:\Python34\lib\site-packages\django\views\generic\base.py" in view
    69.             return self.dispatch(request, *args, **kwargs)
  
  File "C:\Python34\lib\site-packages\django\views\generic\base.py" in dispatch
    89.         return handler(request, *args, **kwargs)
  
  File "C:\Users\***\Desktop\my_app\views.py" in post
    124.          return self.form_invalid(form)
  
  File "C:\Python34\lib\site-packages\django\views\generic\edit.py" in form_invalid
    61.         return self.render_to_response(self.get_context_data(form=form))
  
  File "C:\Python34\lib\site-packages\django\views\generic\edit.py" in get_context_data
    67.         return super().get_context_data(**kwargs)
  
  File "C:\Python34\lib\site-packages\django\views\generic\detail.py" in get_context_data
    93.         if self.object:
  
  Exception Type: AttributeError at /my_app/new_version/999-11/
  Exception Value: 'NewVersionProcessView' object has no attribute 'object'
  </code></pre>
  
  <p>I can provide the urls.py and the htmls if needed.
  Any help is appreciated.</p>