Python – Django Rest Framework – Sends multipart/form data with files and other data to the API

Django Rest Framework – Sends multipart/form data with files and other data to the API… here is a solution to the problem.

Django Rest Framework – Sends multipart/form data with files and other data to the API

I’m trying to create some automated tests for my web application that uses Django and DRF as the backend to handle requests from the frontend.

I’m having trouble finding a way to send some form data to the API using the client, and I’m getting an error stating that no fields are posted.

This is my attempt to use the APITestCase class :

from django.test import TestCase, TransactionTestCase
from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse

from rest_framework.test import APIRequestFactory, APITestCase, APIClient, RequestsClient, APITransactionTestCase

import json, os, re
import requests as python_requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
....
....
def testInvoiceUploadAndRead(self):
        #test non-logged in user
        response=self.client.get(reverse("invoiceupload"))
        self.assertEqual(response.status_code, 403)

user=Account.objects.get(username="test_user")
        self.client.login(username=user.username, password="rebar123")
        response=self.client.get(reverse("invoiceupload"))
        self.assertEqual(response.status_code, 405)
        #create the invoice
        full_filename=os.path.join("media", "testfiles", "sample_file.png")
        invoice = MultipartEncoder(
            fields={
                "invoicefile":("test_file.png", open(full_filename, "rb")),
                "debtor":"5560360793",
                "amount":"55000",
                "serial":"1234567890",
                "dateout":"20180728",
                "expiration":"20180808",
            }
        )
        response=self.client.post(reverse("invoiceupload"), invoice, content_type="multipart/form-data")
        print(response.data["message"])
        self.assertEqual(response.status_code, 201)

I get the error:

{'debtor': [ErrorDetail(string='This field is required.', code='required')], 'invoicefile': [ErrorDetail(string='No file was submitted.', code='required')], ' expiration': [ErrorDetail(string='This field is required.', code='required')], 'dateout': [ErrorDetail(string='This field is required.', code='required')], 'amount': [ErrorDetail( string='This field is required.', code='required')], 'serial': [ErrorDetail(string='This field is required.', code='required')]}

Not detected that something has been sent, any ideas on how to fix it, or a better way to accomplish the same thing?

Solution

Solved this by reading the documentation more closely, which automatically sets multipart/form-data if no content type is passed to the post method, which I accepted.

Variations:

invoice = {
    "invoicefile":(open(full_filename, "rb")),
    "debtor":"5560360793",
    "amount":"55000",
    "serial":"1234567890",
    "dateout":"20180728",
    "expiration":"20180808",
}
response = self.client.post(reverse("invoiceupload"), invoice)
self.assertEqual(response.status_code, 201)

Related Problems and Solutions