sgauri
sgauri

Reputation: 714

request.session is not transferring full querydict to another view

I am submitting a form using 'post' and transferring its data to another view using request.POST but my querydict is incomplete when it arrives in the second view.

view1

def question_filter(request):
    if request.method == 'POST':
        print('before validation', request.POST)
        request.session['question_data'] = request.POST
        return HttpResponseRedirect(reverse('qapp:question_preview'))

view2

def question_preview(request):
    all_questions = Questions.objects.all()
    question_data = request.session.get('question_data')
    print(question_data)
    question_pk_list = question_data['question_pk']
    preview_questions = all_questions.filter(id__in=question_pk_list)
    ...
    return render(request,'apps/qapp/question_preview.html', {somecontext})

Am I doing something wrong here ?

Update:

before validation <QueryDict: {'topics_all': ['1', '2'], 'csrfmiddlewaretoken': ['...'], 'subtopics_all': ['4', '2'], 'classroom': ['3'], 'difficulty': ['l', 'm']}>
[28/Feb/2018 17:17:39] "POST /question/filter/ HTTP/1.1" 302 0

(in the second view)question data {'topics_all': '2', 'csrfmiddlewaretoken': '...', 'difficulty': 'm', 'subtopics_all': '2', 'classroom': '3'}

Upvotes: 2

Views: 450

Answers (3)

interDist
interDist

Reputation: 557

This is somewhat old, but as I stumbled myself because of the same issue, I want to offer a solution for those reaching this question via a search, to storing the whole request.GET or request.POST object in a session without losing data (as opposed to @Exprator’s solution which requires handling each parameter manually).

The core issue is the default serializer Django uses for the session data: django.contrib.sessions.serializers.JSONSerializer. This serializer is not aware of keys associated with multiple values (for them, the getlist() method of QueryDict should be used), which results in only the last value for each key being serialized.

There are two possible solutions:

  • Either manually pickle & unpickle the request.GET or request.POST object when storing & retrieving from a session;
    • This will call the __getstate__() method of QueryDict, see also an old Django ticket.
  • Or, pickle the whole data of the session, by switching to the django.contrib.sessions.serializers.PickleSerializer.

Upvotes: 0

Gal Silberman
Gal Silberman

Reputation: 3884

The session is not saved by default. Add request.session.modified = True:

def question_filter(request):
    if request.method == 'POST':
        print('before validation', request.POST)
        request.session['question_data'] = request.POST
        request.session.modified = True
        return HttpResponseRedirect(reverse('qapp:question_preview'))

https://docs.djangoproject.com/en/2.0/topics/http/sessions/#when-sessions-are-saved

Edit:

You can hack it using json:

import json

def question_filter(request):
    if request.method == 'POST':
        print('before validation', request.POST)
        request.session['question_data'] = json.dumps(request.POST)
        return HttpResponseRedirect(reverse('qapp:question_preview'))

def question_preview(request):
    all_questions = Questions.objects.all()
    question_data = json.loads(request.session.get('question_data'))
    print(question_data)
    question_pk_list = question_data['question_pk']
    preview_questions = all_questions.filter(id__in=question_pk_list)
    ...
    return render(request,'apps/qapp/question_preview.html', {somecontext})

Upvotes: 0

Exprator
Exprator

Reputation: 27503

you cannot send all the post data like that, as you have list inside your input names, you have to access each names differently and set them in the session.

request.session['question_data'] = request.POST.getlist('topics_all')

same for other input names, then access with key in the second view

Upvotes: 2

Related Questions