djangopython-3.xdjango-formsdjango-formwizarddjango-formtools

Passing user.id to class FormWizardView in Django form-tools


I am trying to create a multi-step form in django2.2. Apparently, the native FormWizard was deprecated in previous django versions so the only solution I have ran into is django-formtools. I have two Models that provide the FormWizard with the required fields. I have been able to make a dictionary of user input from the forms successfully. I intend to save this data to one of the models. However, the model requires a user.id field since it is a Foreign key to a CustomUser object and cannot thereby be null. I believe there is a way to add this user.id to the data dictionary then save the entire dict as an instance in my target model. This is where I have been struggling.

I have tried invoking user=request.user but an error occurs saying that 'request is not defined' since this is a class-based view(I guess that's why).

My Models

class Category(models.Model):
    name= models.CharField(blank = True, max_length=500)
    
    def __str__(self):
        return self.name
class ModelsAd(models.Model):
    title = models.CharField(max_length=500)
    category = models.ForeignKey(Category,default=1, on_delete=models.CASCADE)
    location = models.ForeignKey(Location,default=1, blank=True, on_delete=models.CASCADE)
    description = models.CharField(max_length=1000)
    price = models.PositiveIntegerField(default=1000)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

My Forms

all_categories = Category.objects.all()
class CategoryChoiceForm(forms.Form):    
    category = forms.ModelChoiceField(queryset = all_categories, to_field_name = "name", empty_label=None)


class ModelsAdForm(ModelForm):
    class Meta:
        model = ModelsAd
        fields = ('title','location', 'description', 'price')

My Views

from formtools.wizard.views import SessionWizardView

class FormWizardView(SessionWizardView):
    template_name = "post_ad.html"
    form_list = [CategoryChoiceForm, ModelsAdForm]

    def done(self, form_list, **kwargs):
        form_data = [form.cleaned_data for form in form_list]
        data_dict={}
        for item in form_data:
            data_dict.update(item)
        add_data=ModelsAd(**data_dict)
        # add_data.save()
        test=ModelsAd.objects.all()
        print(test)
        return render(self.request, 'index.html',locals())

I need to pass user.id to the FormWizardView so that I can append it to the data_dict so that I can successfully save the dict as an instance in my db. So far, I am running in circles. Any help will be highly appreciated. Someone please at least point me in the right direction


Solution

  • I have to stop answering my own questions but what the heck.. I figured out what the problem was... when I tried invoking request.user in the FormWizardView, it was throwing a 'request' not defined error, so I tried to give the class a request object via self like, user=self.request.user . However, this only produced a user instance belonging to the ModelsAdForm and not to the CustomUser model, as was required by the db... I can't believe it was as simple as calling an instance of CustomUser with the same value as the ModelsAdForm user... what I mean is user=CustomUser.objects.get(email=self.request.user) I therefore amended my FormWizardView to look like this:

    class FormWizardView(SessionWizardView):
        template_name = "post_ad.html"
        form_list = [CategoryChoiceForm, ModelsAdForm]
    
        def done(self, form_list, **kwargs):
            form_data = [form.cleaned_data for form in form_list]
            data_dict={}
            for item in form_data:
                data_dict.update(item)
            data_dict.update({'user':CustomUser.objects.get(email=self.request.user)})
            add_data=ModelsAd(**data_dict)
            add_data.save()
            return render(self.request, 'index.html',locals())
    

    and boom! a form that takes fields from three models and saves input data to one model... Now to make it more dynamic.. refactor hour :)