Ahsaan-566
Ahsaan-566

Reputation: 603

Django CBV UpdateView not saving form to database. (Django 2.0)

I'm new to Django and currently working on a side project. I have two models User and Profile which have one to one relationship.

I have created post_save signal so when a new user signs up, his empty profile instance is already created in the database.

def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

post_save.connect(create_profile, sender=CustomUser)

Since the profile is already created, I thought why not skip the CreateView and use UpdateView to save the profile form.

By doing that I just have to create one form for the profile. So I have only one view that is UpdateView.

When the user creates his account he is directed to the Profile(automatically created) form where he saves(updates) his information.

Now when in updateView template when I submit the form, nothing is saved in the database, however, form successfully saves via admin panel and also fields are being populated correctly from the database since it is an update form. I think the problem lies in posting the data since fields display correct data when saved from admin.

What could be the problem?

View

class ProfileSettingsView(UpdateView):
    model = Profile
    form_class = ProfileSettingsForm
    pk_url_kwarg = 'pk'
    context_object_name = 'object'
    template_name = 'profile_settings.html'

    def get_object(self):
        pk = self.kwargs.get('pk')
        return get_object_or_404(Profile, id=pk)

    def get_context_data(self, **kwargs):
        c_object = self.get_object()
        context = super(ProfileSettingsView, 
        self).get_context_data(**kwargs)

        context['linked_in'] = c_object.linked_in
        context['facebook'] = c_object.facebook
        print('context: ', context)
        return context

Template

<form style="padding-left: 15px; padding-right:15px;" method="POST">
    {% csrf_token %}

    <h3>Basic Information</h3>

    <div class="col-lg-6">
        <div class="form-group">
            <div class="field">
                <label>Facebook<span class="red-txt">*</span></label>
                <input class="form-control" type="text" name="facebook" value="{{ facebook }}" maxlength="60" size="50">
            </div>
        </div>
    </div>

    <div class="col-lg-6">
        <div class="form-group">
            <div class="field">
                <label>Linked In<span class="red-txt">*</span></label>
                <input class="form-control" type="text" name="linked_in" value="{{ linked_in }}" maxlength="60" size="50">
            </div>
        </div>
    </div>

    <div style="padding-bottom:30px; text-align:center;" class="login login-button">
        {# <a href="" class="btn btn-outline-primary btn-lg"></a> #}
        <input type="submit" class="btn btn-outline-primary btn-lg" value="Save Profile">
    </div>
</form>

Model

class Profile(models.Model):
    user          = models.OneToOneField(User, on_delete=models.CASCADE)
    linked_in     = models.CharField(max_length=30, null=True, blank=True)
    facebook      = models.CharField(max_length=30, null=True, blank=True)

Form

class ProfileSettingsForm(forms.ModelForm):

    class Meta:
        model = Profile
        fields = '__all__'

Upvotes: 2

Views: 447

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 600041

You have duplicated a lot of the functionality of the form, view and template, and in doing so you have bypassed the things that would have told you what was wrong.

The specific issue you have is that your form is not valid. This is because you have defined it to expect all three fields on your Profile model, but you are not supplying the user in the submitted data. You don't see this on the page because you are not displaying the errors that the form gives you, nor are you redisplaying the entered data. Both of these things are done for you by Django, but you avoid them by hard-coding the fields in HTML.

In addition, most of your view code is irrelevant. Your view should look like this only:

class ProfileSettingsView(UpdateView):
    model = Profile
    form_class = ProfileSettingsForm
    template_name = 'profile_settings.html'

as all the methods and the other attributes are unnecessary. Your form should be:

class ProfileSettingsForm(forms.ModelForm):

    class Meta:
        model = Profile
        fields = ['linked_in', 'facebook']
        widgets = {
            'linked_in': forms.TextInput({'class': 'form-control'}),
            'facebook': forms.TextInput({'class': 'form-control'}),
        }

And now your template can be just:

<form style="padding-left: 15px; padding-right:15px;" method="POST">

    {{ form.errors }}

    {% csrf_token %}

    <h3>Basic Information</h3>

    <div class="col-lg-6">
        <div class="form-group">
            <div class="field">
                <label>Facebook<span class="red-txt">*</span></label>
                {{ form.facebook }}
            </div>
        </div>
    </div>

    <div class="col-lg-6">
        <div class="form-group">
            <div class="field">
                <label>Linked In<span class="red-txt">*</span></label>
                {{ form.linked_in }}
            </div>
        </div>
    </div>

    <div style="padding-bottom:30px; text-align:center;" class="login login-button">
        {# <a href="" class="btn btn-outline-primary btn-lg"></a> #}
        <input type="submit" class="btn btn-outline-primary btn-lg" value="Save Profile">
    </div>
</form>

Upvotes: 2

Related Questions