Kimmo Hintikka
Kimmo Hintikka

Reputation: 15470

Why Django forces me to upload an image if I upload a file?

I have this really simple Django-Rest-Framework task app which does now behave the way I expect.

Both image and file upload work so does the url routing their urls. However when I upload only Doc to new Task I get following error >

{
    "image": [
        "The submitted data was not a file. Check the encoding type on the form."
    ]
} 

Note that I just added the blank=True field behaviour was same without it. the default No-img.jpg and No-doc.pdf files exist and route fine.

Here is my TaskApp/models.py

from django.db import models


class Task(models.Model):
    task_name = models.CharField(max_length=20)
    task_desc = models.TextField(max_length=200)
    completed = models.BooleanField(default=False)
    date_created = models.DateTimeField(auto_now_add=True, auto_created=True)
    image = models.ImageField(upload_to='Images/', default='Images/None/No-img.jpg', blank=True)
    doc = models.FileField(upload_to='Doc/', default='Doc/None/No-doc.pdf')

    def __str__(self):
        return '{}'.format(self.task_name)

# TODO try to understand why this model requires image upload

Here is my TaskApp/serializers.py

from rest_framework import serializers from .models import Task

class TaskSerializer(serializers.ModelSerializer):

    image = serializers.ImageField(max_length=None, use_url=True)
    doc = serializers.FileField(max_length=None, use_url=True)

    class Meta:
        model = Task
        fields = ('id', 'task_name', 'task_desc', 'completed', 'date_created', 'image', 'doc')

Here is my TaskApp/views.py

from rest_framework import viewsets, filters from .models import Task from .serializers import TaskSerializer

class TaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.all()  # We use filters for ordering by part
    serializer_class = TaskSerializer
    filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter, filters.SearchFilter)
    filter_fields = ('completed',)
    ordering = ('-date_created',)
    search_fields = ('task_name',)

Here is my TaskAPI/urls.py

from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
from TaskApp import views
from django.conf.urls.static import static
from django.conf import settings

router = routers.DefaultRouter()
router.register(r'task', views.TaskViewSet)
# router.register(r'due_task', views.DueTaskViewSet)
# router.register(r'completed_task', views.CompletedTaskViewSet)

urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^admin/', admin.site.urls),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

I am not sure why this behaves the way it does. Any help is highly appreciated.

Upvotes: 0

Views: 2544

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599708

The problem is your serializer. You have overridden the definitions for image and doc; as with ModelForms, when you redefine a field in a model serializer you redefine all its options; including, in this case, whether it is required. You will need to declare that explicitly:

class TaskSerializer(serializers.ModelSerializer):

    image = serializers.ImageField(max_length=None, use_url=True, required=False)
    doc = serializers.FileField(max_length=None, use_url=True)

Upvotes: 4

Related Questions