'How can i submit a form with logged in user as default?

After you sign up, you are prompted to the login page, and after you login, you are redirected to another page that contains a form used for gathering additional information about the new user. The problem is that the form doesn't submit if i don't specify the {{form.user}} instance in the html file. Probably because the user_id is not recognized by default. When i specify it, the form let me chooses from already existing users, and i would like it to go with the logged in user by default.

models

class AdditionalInfoModel(models.Model):
    objects = None
    skill_choices = (('Beginner', 'BEGINNER'),
                 ('Intermediate', 'INTERMEDIATE'),
                 ('Expert', 'EXPERT'))

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    location = models.CharField(max_length=30, blank=True)
    assumed_technical_ski_level = models.CharField(max_length=30, choices=skill_choices)
    years_of_experience = models.PositiveIntegerField(blank=True)
    money_to_spend = models.PositiveIntegerField(blank=True)
    def __str__(self):
        return self.user.username

views

class CreateInfoView(LoginRequiredMixin, CreateView):
    model = AdditionalInfoModel

    form_class = AdditionallnfoModelForm
    template_name = "user_ski_experience/additional_info.html"
    
    def get_form_kwargs(self):
        variable_to_send = super(CreateInfoView, 
        self).get_form_kwargs()
        variable_to_send.update({'pk': None})
        return variable_to_send

    def get_success_url(self):
        return reverse('aplicatie2:home')

forms

class AdditionallnfoModelForm(forms.ModelForm):
    class Meta:
        model = AdditionalInfoModel
        fields = '__all__'

    def __init__(self, pk,  *args, **kwargs):
        super(AdditionallnfoModelForm, self).__init__(*args, 
        **kwargs)
        self.pk = pk

    def clean(self):
        return self.cleaned_data

html

{% load crispy_forms_tags %}
{% block content %}
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>

    <form method="post">
        {% csrf_token %}
        <h1> Let's get started with some questions ! </h1>
        <h2> This will help us get to know your ski experience 
        </h2>
        <li> Your user name is: {{form.user|as_crispy_field}}</li>
        <li> Where do you live ?    
            {{form.location|as_crispy_field}}  </li>
        <li> How would you rank yourself as a skier ?    
            {{form.assumed_technical_ski_level|as_crispy_field}}  
       </li>
        <li> How many years of ski experience do you have ?    
            {{form.years_of_experience|as_crispy_field}}  </li>
        <li>  How much ar you willing to spend ?    
            {{form.money_to_spend|as_crispy_field}}  </li>

        <button type="submit" onclick = "{% url 'aplicatie2:home' 
            %}">Submit</button>
    </form>

</body>

{% endblock %}

the log in and sign up are done using standard django models



Solution 1:[1]

I suggest using a disabled field and setting the initial value of the user through the initializer method of the form. The disabled fields are completely ignored in the POST requests so user will not be able to change the default user you set through that field.

Django docs on the disabled attribute: https://docs.djangoproject.com/en/4.0/ref/forms/fields/#disabled

views.py

class CreateInfoView(LoginRequiredMixin, CreateView):
    model = AdditionalInfoModel

    form_class = AdditionallnfoModelForm
    template_name = "user_ski_experience/additional_info.html"
    
    def get_form_kwargs(self):
        variable_to_send = super(CreateInfoView, 
        self).get_form_kwargs()
        variable_to_send.update({'pk': None})
        variable_to_send.update({'pk_user': self.request.user.pk})
        return variable_to_send

    def get_success_url(self):
        return reverse('aplicatie2:home')

forms.py

class AdditionallnfoModelForm(forms.ModelForm):
    class Meta:
        model = AdditionalInfoModel
        fields = '__all__'

    def __init__(self, pk, *args, **kwargs):
        pk_user = kwargs.pop('pk_user')
        super(AdditionallnfoModelForm, self).__init__(*args, 
        **kwargs)
        self.pk = pk

        # Make the user field readonly
        self.fields['user'].disabled = True
        self.fields['user'].initial = pk_user

    def clean(self):
        return self.cleaned_data

EDIT: also found issues in your HTML. The form won't submit because your HTML is not correct for form submitting. Something like below should work:

{% load crispy_forms_tags %}
{% block content %}
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>

    <!-- Place the POST endpoint URL in the action attribute of the 'form' tag -->
    <form method="post" action="{% url 'aplicatie2:home' %}">
        {% csrf_token %}
        <h1> Let's get started with some questions ! </h1>
        <h2> This will help us get to know your ski experience 
        </h2>
        <li> Your user name is: {{form.user|as_crispy_field}}</li>
        <li> Where do you live ?    
            {{form.location|as_crispy_field}}  </li>
        <li> How would you rank yourself as a skier ?    
            {{form.assumed_technical_ski_level|as_crispy_field}}  
       </li>
        <li> How many years of ski experience do you have ?    
            {{form.years_of_experience|as_crispy_field}}  </li>
        <li>  How much ar you willing to spend ?    
            {{form.money_to_spend|as_crispy_field}}  </li>

        <!-- You can't use <button> element for submitting a form without special JS -->
        <input type="submit">Submit</button>
    </form>

</body>

{% endblock %}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1