pythondjangoformview

Django: 'UtilisateurUpdateView' object has no attribute 'object'


I develop a Django project with inlineformset nested using FormView.

I first develop my form using CreateView/UpdateView and it works but when I use FormView I got an error

'UtilisateurUpdateView' object has no attribute 'object'

Why I can get access 'object' when I use UpdateView but not with FormView ?

I have read that it could come from override method but here doesn't seems to be the case ?

forms.py

NAME = Thesaurus.options_list(2,'fr')
ACCESS = Thesaurus.options_list(3,'fr') 
ApplicationFormset = inlineformset_factory(
    UtilisateurProjet, Application, #Utilisateur, Application,
    fields=('app_app_nom','app_dro'),
    widgets={
        'app_app_nom': forms.Select(choices=NAME),
        'app_dro': forms.Select(choices=ACCESS)
    },
    extra=3,
    can_delete=True,
)

class UtilisateurProjetUpdateForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request")
        super(UtilisateurProjetUpdateForm, self).__init__(*args, **kwargs)

        self.fields["pro_ide"] = forms.ModelChoiceField(queryset = PROJETS, label = "Nom projet", widget = forms.HiddenInput(), initial = Projet.objects.get(pro_ide=self.request['projet']))
        self.fields["uti_ide"] = forms.ModelChoiceField(queryset = UTILISATEURS, label = "Nom, prénom de l'utilisateur", widget = forms.Select, initial = Utilisateur.objects.get(uti_ide=self.request['utilisateur']))

    class Meta:
        model = UtilisateurProjet
        fields = ('pro_ide','uti_ide',)

views.py

class UtilisateurUpdateView(FormView):
    template_name = 'project/utilisateurprojet_form.html'
    form_class = UtilisateurProjetUpdateForm

    def get_form_kwargs(self):
        kwargs = super(UtilisateurUpdateView, self).get_form_kwargs()
        kwargs['request'] = dict(utilisateur = self.kwargs['pk'], projet = self.kwargs['projet'])
        # kwargs['request'] = self.request
        # print('projet',self.kwargs['projet'])
        # print('utilisateur',self.kwargs['pk'])
        return kwargs

    def get_context_data(self, **kwargs):
        data = super(UtilisateurUpdateView,self).get_context_data(**kwargs)
        # print('projet',self.kwargs['projet'])
        # print('utilisateur',self.kwargs['pk'])
        instance = UtilisateurProjet.objects.get(pro_ide=self.kwargs['projet'],uti_ide=self.kwargs['pk'])
        data['projet'] = Projet.objects.get(pro_ide=self.kwargs['projet'])
        data['utilisateur_app'] = Utilisateur.objects.get(uti_ide=self.kwargs['pk'])
        if self.request.POST:
            data["utilisateur"] = self.request.user.username
            data["user_profil"] = self.request.session.get('user_profil')
            data["application"] = ApplicationFormset(self.request.POST, instance=instance)
        else: 
            data["application"] = ApplicationFormset(instance=instance)
        return data

    def form_valid(self, form):
        # Setting commit to False will return the object without saving it to the Database.
        self.object = form.save(commit=False)
        context = self.get_context_data()
        application = context["application"]
        user_profil = context["user_profil"]
        if user_profil == 'Investigateur':
            self.object.uti_val = 0 # demande modifiée par investigateur -> repasse à non validée + envoie de mail
        elif user_profil == 'Moniteur':
            self.object.uti_val = 1 # demande validée par moniteur -> validée + envoie de mail
            self.object.uti_val_dat = timezone.now()
        else:
            self.object.uti_val = 0
        # After doing our own changes to the object, we can save it.
        self.object.save()

        if application.is_valid():
            # Not sure what is happening here, but this statement does nothing by itself.
            # form.instance = self.object
            application.save()

        return super().form_valid(form)

    def get_success_url(self):
        return reverse("project:index")

Solution

  • FormView and DetailView are different classes from different packages: django.views.generic.edit.FormView and django.views.generic.detail.DetailView respectively.

    From the docs of DetailView:

    While this view is executing, self.object will contain the object that the view is operating upon.

    FormView doesn't have an object property, because it doesn't necessarily work with an object.

    However, since you're using ModelForms, you should be able to access the Form's object after calling form.save():

    def form_valid(self, form):
            # Setting commit to False will return the object without saving it to the Database.
            self.object = form.save(commit=False)
            context = self.get_context_data()
            application = context["application"]
            user_profil = context["user_profil"]
            self.object.uti_val = 1
            self.object.uti_val_dat = timezone.now()
            else:
                self.object.uti_val = 0
            # After doing our own changes to the object, we can save it.
            self.object.save()
    
            if application.is_valid():
                # Not sure what is happening here, but this statement does nothing by itself.
                form.instance = self.object
                application.save()
    
            return super().form_valid(form)