I have 2 models Task
and TaskImage
which is a collection of images belonging to Task
object.
What I want is to be able to add multiple images to my Task
object, but I can only do it using 2 models. Currently, when I add images, it doesn't let me upload them and save new objects.
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
serializers.py
class TaskImageSerializer(serializers.ModelSerializer):
class Meta:
model = TaskImage
fields = ('image',)
class TaskSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
images = TaskImageSerializer(source='image_set', many=True, read_only=True)
class Meta:
model = Task
fields = '__all__'
def create(self, validated_data):
images_data = validated_data.pop('images')
task = Task.objects.create(**validated_data)
for image_data in images_data:
TaskImage.objects.create(task=task, **image_data)
return task
models.py
class Task(models.Model):
title = models.CharField(max_length=100, blank=False)
user = models.ForeignKey(User)
def save(self, *args, **kwargs):
super(Task, self).save(*args, **kwargs)
class TaskImage(models.Model):
task = models.ForeignKey(Task, on_delete=models.CASCADE)
image = models.FileField(blank=True)
However, when I do a post request:
I get the following traceback:
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner 41. response = get_response(request)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response 187. response = self.process_exception_by_middleware(e, request)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response 185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view 58. return view_func(*args, **kwargs)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/viewsets.py" in view 95. return self.dispatch(request, *args, **kwargs)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in dispatch 494. response = self.handle_exception(exc)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception 454. self.raise_uncaught_exception(exc)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/views.py" in dispatch 491. response = handler(request, *args, **kwargs)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/mixins.py" in create 21. self.perform_create(serializer)
File "/Users/gr/Desktop/PycharmProjects/godo/api/views.py" in perform_create 152. serializer.save(user=self.request.user)
File "/Applications/Anaconda/anaconda/envs/godo/lib/python3.6/site-packages/rest_framework/serializers.py" in save 214. self.instance = self.create(validated_data)
File "/Users/gr/Desktop/PycharmProjects/godo/api/serializers.py" in create 67. images_data = validated_data.pop('images')
Exception Type: KeyError at /api/tasks/ Exception Value: 'images'
You have
read_only
set to true inTaskImageSerializer
nested field. So there will be no validated_data there.Description for the issue
The origin of the exception was a
KeyError
, because of this statementimages_data = validated_data.pop('images')
. This is because the validated data has no keyimages
. This means the images input doesn't validate the image inputs from postman.Django post request store
InMemmoryUpload
inrequest.FILES
, so we use it for fetching files. also, you want multiple image upload at once. So, you have to use different image_names while your image upload (in postman).Change your
serializer
to like this,I don't know about your view, but i'd like to use
ModelViewSet
prefferable view class
Postman Console
DRF-Result
UPDATE
This is the answer for your comment. In django
reverse foreignKey
are capturing using_set
. see this official doc. Here,Task
andTaskImage
are inOneToMany
relationship, so if you have oneTask
instance, you could get all relatedTaskImage
instance by thisreverse look-up
featurehere is the example
Here this
task_img_set_all
will be equal toTaskImage.objects.filter(task_id=1)