Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework - Send multipart/form-data with file and other data to API

I'm trying to create some automated tests for my web-app which uses Django and DRF as a back-end to hand requests from the front-end.

I'm having trouble finding a way to use the client to send some form-data to the API, I'm getting an error that no fields were posted.

Here is my attempt using 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'm getting 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')]}

No detected content sent, any ideas on how I can fix it, or better ways to accomplish the same thing?

like image 860
Marcus Grass Avatar asked Nov 23 '25 21:11

Marcus Grass


1 Answers

Solved it by reading the docs more closely, if no content type is passed to the post method it automatically sets multipart/form-data, which my view accepted.

Changes:

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)
like image 106
Marcus Grass Avatar answered Nov 25 '25 09:11

Marcus Grass