How to retrieve form context at POST request processing time

I have a form that contains a table with rows that reflect course objects from a database . Each row contains a checkbox input .

When the form is submitted , I want to update which courses are checked and unchecked into the user profile.

To do that I need to know which inputs are checked , which I know how to retrieve, but I also need to know which inputs are unchecked . This is not as easy as ‘all the others’ because my table does not always contain all course objects from the database. Its often a filtered set.

So I need to know which courses are present in the table. Of course I know this at rendertime, but I dont know how to retrieve it at POST request processing time.

I read something about using hidden inputs , which I could give a try. The idea would be to give each row a hidden input with the course id, which I can retrieve when the form is submitted.

I am curious if this would be the way to go. Or if there is a better solution to this issue .

Hi @jnoordzij87!

Please post your code in order to understand your question (views, models, templates and use code blocks).

Hi please see underneath .
The question is in update_user_interests() function :
How do I retrieve the courses that are in the table ?

Form :

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" name="submit" value='Submit'/>
    {% for filter in filters%}
    <input type="submit" name="filter" value='{{filter}}'/>
    {% endfor %}
    <table class="table table-striped table-bordered">
        <tbody>
            {% for course in courses %}
                <tr>
                    <td>
                        <input type="checkbox" 
                        name="checks" 
                        value={{course.reference}}
                        {% if course in user_interests %} checked {% endif %}>
                    </td>
                    <td>
                        {{ course.reference|default:"" }}
                    </td>
                    <td>
                        {{ course.name|default:"" }}
                    </td>
                    <td>
                        {{ course.description|default:"" }}
                    </td>
                </tr>
            {% endfor %}
        </tbody>
    </table>

</form>

View:

def table(request):
    profile = Profile.objects.get(user=request.user.id)
    allcourses = Course.objects.all()
    filteropts = ['A','B','C']
    
    if request.method == 'GET': 
        tablecourses = allcourses
        user_interests = profile.interests.all()
        
    if request.method == 'POST':
        # update user interests from submitted form
        update_user_interests(request, profile)
        user_interests = profile.interests.all()
        # filter the table if filter button clicked
        filter = get_filter(request)
        if filter:
            tablecourses = Course.objects.filter(curriculum=filter).values()
        else:
            tablecourses = allcourses
        
    return render(request, 'table.html',
        {'courses': tablecourses,
         'user_interests' : user_interests,
         'filters':filteropts})

Helpers :

def get_filter(request):
    if 'filter' in request.POST:
        return request.POST.getlist("filter")[0]

def update_user_interests(request, profile):
    tablecourses = [] # How do I retrieve the courses that are in the form table ???? 
    checked_courses = request.POST.getlist("checks")
    for course in tablecourses:
        ref = course.reference
        if ref in checked_courses:
            profile.interests.add(coursemodel)
        else:
            profile.interests.remove(coursemodel)
    profile.save()

Models :

class Course(models.Model):
    name = models.CharField(
        unique=False,
        null=False,
        blank=False,
        max_length=250
    )
    reference = models.CharField(
        unique=True,
        null=False,
        blank=False,
        max_length=250
    )
    curriculum = models.CharField(
        unique=False,
        null=True,
        blank=True,
        max_length=250,
    )
    description = models.TextField(
        unique=False,
        null=True,
        blank=True,
        max_length=2000,
    )

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    interests = models.ManyToManyField(
        Course,
        related_name='interests')

So the courses in the table are already being passed to the template as courses.

def table(request):
    profile = Profile.objects.get(user=request.user.id)
    allcourses = Course.objects.all()
    filteropts = ['A','B','C']
    
    if request.method == 'GET': 
        tablecourses = allcourses
        user_interests = profile.interests.all()
        
    if request.method == 'POST':
        # filter the table if filter button clicked
        filter = get_filter(request)
        if filter:
            tablecourses = Course.objects.filter(curriculum=filter)
        else:
            tablecourses = allcourses
        
        # update user interests from submitted form
        update_user_interests(request, profile, tablecourses)
        user_interests = profile.interests.all()
        
    return render(request, 'table.html',
        {'courses': tablecourses,
         'user_interests' : user_interests,
         'filters':filteropts})

and now you can modify your update_user_interests to accept tablecourses as a parameter:

def update_user_interests(request, profile, tablecourses):
    checked_courses = request.POST.getlist("checks")
    for course in tablecourses:
        if course.reference in checked_courses:
            profile.interests.add(course)
        else:
            profile.interests.remove(course)
    profile.save()

Finally, when a course is checked in the form, will be added to interests.
The courses that are unchecked in the form are removed from interests.
Is that the desired behaviour?