GXM100
GXM100

Reputation: 467

<ForeignKey> is not JSON serializable Django App

I am receiving the error is not JSON serializable when I attempt to do the below in my view. Could someone please assist - I am completely unfamiliar with what this means.

views.py

....
def PackingListView(request):
    if request.method == "POST":
        form = PackingListForm(request.POST)
        if form.is_valid():
            if 'preview' in request.POST:
                request.session['data'] = form.cleaned_data
                return redirect('myview')

            elif 'save' in request.POST:

                form.save()

                context = request.session['data'] = form.cleaned_data #get the from the form
                pdf = render_to_pdf('packlist_preview.html', context) #create the PDF
                filename = "YourPDF_Order{}.pdf" #name the PDF


                instance = PackingListDocuments.objects.create() #create a new instance in the model to contain the doc
                instance_key = instance.pk #get the pk of that new model object
                object = PackingListDocuments.objects.get(pk=instance_key) #get that object
                object.Reference_Number = form.cleaned_data.get('Reference_Number')
                object.PackingListDocument.save(filename, File(BytesIO(pdf.content))) #save the document to that object


                messages.success(request, "Success: Packing List Has Been Created!")
                return redirect('HomeView')

    else:
        form = PackingListForm()
        return render(request, 'packlist.html', {'form': form})

Reference_Number is a foreignkey to the Shipment model which I suppose is why I'm getting this error but I have no idea why or what I might do differently

models.py

class Shipment(models.Model):

    Reference_Number = models.CharField(max_length=100)
    Ultimate_Consignee = models.CharField(max_length=100)

class PackingListDocuments(models.Model):
    Reference_Number = models.ForeignKey(Shipment, null=True, default=None)
    PackingListDocument = models.FileField(upload_to='media')

forms.py

class PackingListForm(forms.ModelForm):
    class Meta:
        model = PackingList
        fields = ['Exporter', 'Consignee', 'Reference_Number', ...]

TRACEBACK

Environment:


Request Method: POST
Request URL: http://127.0.0.1:8000/create/packing_list

Django Version: 1.11
Python Version: 2.7.10
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'Poseidon',
 'crispy_forms',
 'bootstrap_modal_forms']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Library/Python/2.7/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/Library/Python/2.7/site-packages/django/utils/deprecation.py" in __call__
  142.             response = self.process_response(request, response)

File "/Library/Python/2.7/site-packages/django/contrib/sessions/middleware.py" in process_response
  58.                             request.session.save()

File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/db.py" in save
  83.         obj = self.create_model_instance(data)

File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/db.py" in create_model_instance
  69.             session_data=self.encode(data),

File "/Library/Python/2.7/site-packages/django/contrib/sessions/backends/base.py" in encode
  98.         serialized = self.serializer().dumps(session_dict)

File "/Library/Python/2.7/site-packages/django/core/signing.py" in dumps
  93.         return json.dumps(obj, separators=(',', ':')).encode('latin-1')

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py" in dumps
  250.         sort_keys=sort_keys, **kw).encode(obj)

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py" in encode
  207.         chunks = self.iterencode(o, _one_shot=True)

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py" in iterencode
  270.         return _iterencode(o, 0)

File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py" in default
  184.         raise TypeError(repr(o) + " is not JSON serializable")

Exception Type: TypeError at /create/packing_list
Exception Value: <Shipment: 219002> is not JSON serializable

Upvotes: 0

Views: 546

Answers (2)

FiddleStix
FiddleStix

Reputation: 3721

Okay, I haven't worked on Django 1.11 in a while but it looks like there's some duplication and you can let the model form do more of the work for you. I can't test it but I think your view should be more like:

        elif 'save' in request.POST:
            # get a packing list doc from our form but don't save to the db yet
            packing_list_doc = form.save(commit=False)

            context = request.session['data'] = form.cleaned_data  # get the from the form

            pdf = render_to_pdf('packlist_preview.html', context)  # create the PDF

            # what's the point of this? we never use filename...
            filename = "YourPDF_Order{}.pdf"  # name the PDF

            # we already have our packing_list_doc so no need to create one or query one
            # also, the form should have already set the shipment/reference_number on our packing_list_doc

            # for the love of God, please rename PackingListDocument to packing_list_pdf or similar
            # PackingListDocuments.PackingListDocument is not an easy read
            packing_list_doc.PackingListDocument = File(BytesIO(pdf.content))
            packing_list_doc.save()  # because we did commit=False earlier

            messages.success(request, "Success: Packing List Has Been Created!")
            return redirect('HomeView')

Upvotes: 1

dirkgroten
dirkgroten

Reputation: 20682

You're storing data in your session and to do that, Django needs to serialise the data, read this. You'll read that the default serializer used is the JSONSerializer.

Now form.cleaned_data isn't necessarily serialisable to JSON. Any foreign key submitted as integer (id) becomes the actual object in cleaned_data. E.g. form.cleaned_data['Reference_Number'] is a Shipment instance, not its id.

So session['data'] = form.cleaned_data is raising this error.

You need to manually create the dictionary you want to store in the session to ensure it's serialisable.

Upvotes: 2

Related Questions