Jay Jung
Jay Jung

Reputation: 1895

Why is my instance in the ModelForm coming through as a NoneType?

I'm trying to obtain a Profile object within a forms.py ModelForm.

print(type(self.instance)) will return <class 'user_profile.models.Profile'> as expected, but print(self.instance) will return an error: AttributeError: 'NoneType' object has no attribute 'username'

First the form:

class PublicToggleForm(ModelForm):

    class Meta:
        model = Profile
        fields = [
            "public",
        ]

    def clean_public(self):
        public_toggle = self.cleaned_data.get("public")
        if public_toggle is True:
            print(type(self.instance))
            print(self.instance)  
        return public_toggle  

Here is the model:

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL,
                                on_delete=models.CASCADE,
                                null=True, blank=True, related_name='is_profile_to')  
    def __str__(self):
         return self.user.username  

The AUTH_USER_MODEL:

class User(AbstractUser):

    def __str__(self):
        return self.username

I didn't actually set the username field myself. I used django-allauth, and I assume they have a username field.

Returning the Profile object as a string representation of it's User's username hasnt given me problems before. So could it be related to the way that my form is indirectly tied to the view?
I have a FormView, and a DetailView into which the form is inserted:

This is the extent of the FormView:

class PublicToggleFormView(AjaxFormMixin, FormView):
    form_class = PublicToggleForm
    success_url = '/form-success/'
    template_name = 'user_profile/profile_detail.html'  

And the DetailView:

from .forms import PublicToggleForm  

class ProfileDetailView(DetailView):
    template_name = 'user_profile/profile_detail.html'  

    def get_context_data(self, **kwargs):
        context = super(ProfileDetailView, self).get_context_data(**kwargs)
        profile = Profile.objects.get(
            user__username=self.request.user)
        context['public_toggle_form'] = PublicToggleForm(instance=profile)
        return context  

Upvotes: 1

Views: 206

Answers (1)

neverwalkaloner
neverwalkaloner

Reputation: 47354

If I understood your problem correctly, when you calling PublicToggleFormView you don't pass current user's profile instance to the form. You can override get_form_kwargs method to do this:

class PublicToggleFormView(AjaxFormMixin, FormView):
    form_class = PublicToggleForm
    success_url = '/form-success/'
    template_name = 'user_profile/profile_detail.html'  

    def get_form_kwargs(self):
        kwargs = super(PublicToggleFormView, self).get_form_kwargs()
        profile = Profile.objects.get(user=self.request.user)
        kwargs.update({'instance': profile})
        return kwargs

Upvotes: 1

Related Questions