I am trying to create a simple restful API using Django-ninja
.
Here is the post
method to add a new record:
@router.post('/add',
response={201: WordSchema, 401: DefaultSchema, 404: DefaultSchema},
tags=["Dictionary"])
def add_word(request, lang1: str, lang2: str, word_class: int = None,
description: str = None, example: str = None,
sound: UploadedFile = None, image: UploadedFile = None):
if not request.auth.is_superuser:
return 401, {"detail": "Unauthorized"}
try:
if word_class is not None:
word_class = WordClass.objects.get(pk=word_class)
word = Word.objects.create(
created_by=request.auth, lang1=lang1, lang2=lang2,
word_class=word_class,
description=description,
example=example,
sound=sound,
image=image
)
return 201, word
except WordClass.DoesNotExist:
return 404, {"detail": "WordClass Does not exist"}
This endo point works without a problem. The next step is to create a put
endpoint.
@router.put('/put',
response={200: DefaultSchema, 201: WordSchema,
401: DefaultSchema, 404: DefaultSchema,
409: DefaultSchema},
tags=["Dictionary"])
def put_word(request, item_id: int, lang1: str, lang2: str,
description: str = None, example: str = None,
word_class: int = None, sound: UploadedFile = None,
image: UploadedFile = None):
if not request.auth.is_superuser:
return 401, {"detail": "Unauthorized"}
try:
if word_class is not None:
word_class = WordClass.objects.get(pk=word_class)
word = Word.objects.get(pk=item_id)
word.lang1 = lang1
word.lang2 = lang2
word.word_class = word_class
word.description = description
word.example = example
word.sound = sound
word.image = image
word.save()
return 200, {"detail": "Record updated"}
except WordClass.DoesNotExist:
return 404, {"detail": "WordClass Does not exist"}
except Word.DoesNotExist:
word = Word.objects.create(created_by=request.auth,
lang1=lang1, lang2=lang2,
word_class=word_class,
sound=sound, image=image)
return 201, word
Unfortunately, the put
endpoint does not work as intended. There is no error raised but the file fields are neither sending the files nor getting a value (The value is None).
I used the swagger and uploaded the file using it.
But file upload does not work.
If I change the HTTP Method to POST
it works. But it does not work with PUT
method.
Found where the problem lies. It was not on my side but on the django-ninja
's side. The framework does not support file upload with PUT
and PATCH
methods.
However, there is a solution:
https://github.com/vitalik/django-ninja/pull/719, https://pypi.org/project/ninja-put-patch-file-upload-middleware/
First, install the middleware:
pip install ninja-put-patch-file-upload-middleware
Add it on settings file:
# settings.py
MIDDLEWARE = [
...
"ninja_put_patch_file_upload_middleware.middlewares.process_put_patch",
]
Now the PUT
and PATCH
methods will accept file uploads.
Please be aware that this solution lacks the ability to unit test the code using Django
's builtin TestCase
class.