AttributeError at /Column-Create: object has no attribute 'instance'

I’m trying to submit a Column model, but it throws me an error when I clicked a submit button:

the error:
'ColumnForm' object has no attribute 'instance'

Forms.py:

class ColumnForm(forms.Form):
    class Meta:
         model = Column
         fields = ['name', 'selec_type']

Models.py:

class Column(models.Model):
     user = OneToOneFields (settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
     name = models.CharField(max_length=100)
     selec_type = models.ForeignKey(Type, on_delete= models.CASCADE)

Views.py:

from django.views.generic.edit import FormView
from django.forms import modelformset_factory
from .forms import ColumnForm
from .models import Column

ColumnForm objects has no attribute instance

class ColumnCreate(FormView):
    template_name = 'design.html'
    form_class = modelformset_factory(Column, form=ColumnForm, extra=30)
    success_url = '/'

    def form_valid(self, form):
        form.instance.user = self.request.user
        form.save()
        return super().form_valid(form)

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(formset=form))

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['formset'] = context['form']
        return context
<form method='post'>
    {% csrf_token %}
{{ formset.management_form}}
   {% for form in formset %}
        {{form.as_p}}
   {% endfor %}
<button type='submit'>Save<button/>
<form/>

It looks like you’re trying to use a formset as if it were a form. A formset is not a form. It’s an object that serves as a container for a list of forms. You cannot use the formset as if it were a form. If you’re using a formset with the Django-provided CBVs, you probably want to base it on View and not FormView.

Then, modelFormSet can only be submitted using Function Base View not Class Base View?

That is not an accurate conclusion.

It is true that the Django-provided generic editing CBVs are designed around the idea of working with single instances of a single model. And yes, it’s also true that expanding those views to include multiple models or formsets is probably more work than the benefit that you will see.

However, this does not mean that you can’t construct CBVs to work in those situations. The Django-provided generic CBVs are not the only CBVs that can be created. It’s certainly possible to build generic CBVs designed to work with formsets or a “base model” with a formset.

So yes. A model formset can be processed by a CBV. It’s just that you’re likely going to want to use View as your base class for the view and not one of the more detailed classes.

1 Like

Ken, I don’t know how to allow a user to submit a form that includes a user in the model. I fell in love with a Class-Based View, but using a Function-Based View to submit a form that includes a user is difficult for me.

I know how to submit the form using a Class-Based View, but I can’t do it with a Function-Based View.

using Class Base View:

class CreateColumn(CreateView): 
     model = Column
     form_class = ColumnForm
     template_name = 'create_column.html' 
     success_url = reverse_lazy('Home')  
          
  
     def form_valid(self, form): 
         form.instance.user = self.request.user 
         return super(CreateColumn, self).form_valid(form)

Since my Column model has user in it, as you can see down here, I do not include the user when submitted the form, that is why I’m using class base view to submit the form.

def design(request):
    ColumnFormSet = modelformset_factory(Column, fields = ('name', 'selec_type'), extra=30)
    formset = ColumnFormSet
    if request.method == 'POST':
        formset = ColumnFormSet(request.POST)
        if formset.is_valid():
            formset.save()
            return redirect('Home')
    else:
        formset = ColumnFormSet()
    return render (request, 'design.html', {'formset':formset})

In your CBV, Django saves the request in the instance of the view. This means that you have access to the request as self.request.

In an FBV, the request is the first parameter of the function:

It’s the same type of object (an HttpRequest object), with all the same attributes as the request made available to you as self.request in a CBV. Whatever you do with self.request in a CBV can be done with request in the FBV.

You may want to review the docs at examples at Working with forms | Django documentation | Django and Creating forms from models | Django documentation | Django as well as looking as the source code for the CBVs to understand how a CBV is just a (very) fancy FBV written as a Python class.