Search code examples
pythondjangodjango-viewsdjango-serializerdjango-sessions

How to deserialize a serialized queryset in Django?


views.py

def ipd_report_view(request):
    report=IpdReport.objects.all()
    myFilter=IpdFilters(request.POST, queryset=report)
    report=myFilter.qs
    total1=report.aggregate(Sum('realization__amount_received'))
    total2=report.aggregate(Sum('realization__deficit_or_surplus_amount'))
    rp=serializers.serialize('json', report)
    request.session['report']=rp
    context={'report': report, 'total1':total1, 'total2':total2, 'myFilter':myFilter}
    return render(request, 'account/ipdreport.html', context)

In another view function, I have to use the data in the session to be able to make the function export the data to an excel file.

I did rp=request.session['report'], but this object is a string object, so how do I go about converting this back to a queryset? Or is there any other way to achieve this?


Solution

  • The question specifically asks about getting a QuerySet back so it's worth noting that calling serializers.deserialize (per @cabesuon's answer) will not do that - it returns a generator yielding DeserializedObject. If that's not good enough for your use-case you may want to reconstruct a QuerySet:

    IpdReport.objects.filter(
        pk__in=map(
            lambda o: o.object.pk,
            serializers.deserialize("json", request.session["report"]),
        )
    )
    

    Edit: to elaborate a bit more on what's happening here:

    Django documentation about serialization notes:

    The Django object itself can be inspected as deserialized_object.object.

    Further, the pk property of that Django object is provided by Django as a convenient way of making use of the primary key.

    Essentially what we're doing with the functional programming map() construct is turning our returned generator of DeseralizedObject instances into a sequence of just primary keys. The lambda's entire purpose is to access our desired properties (it's equivalent to operator.itemgetter("object.pk") but doesn't require importing the operator module and is more immediately obvious). After that, we pass that resulting sequence to .filter() to do a lookup of IpdReport instances that ended up in the QuerySet that you serialized.

    If you want to read more about functional programing in python you may want to check out the HOWTO on the topic.

    It's also worth noting that this entire approach has a potentially significant downside - the state of the database may be altered between serialization and deserialization - this can cause some inconsistencies (getting results that no longer match previously applied filters or, inversely - not getting results that should match the filters but previously didn't). For that reason you may want to look into serializing QuerySet.query.