0๐
So, after a few hours of research I was able to find my own solution. The method used to read multiple files, was taken from this answer. By breaking the [object FileList] into separate files and appending them to the FormData. The models are based on this answer
On the backend, overriding the create method of the serializer and loop through resquest.POST.data excluding unwanted keys to access the just the files. And saving them into the Images model (should be named PostImage).
Note that I do no access the validated_data for the files, instead they are retrieved directly from the request.
I used bootstrap5 in the frontend.
EDIT: Tested only two types of request GET(list) and POST(create) (as you see in vue component)
models.py:
class Post(models.Model):
title = models.CharField(max_length=128)
body = models.CharField(max_length=400)
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
serializers.py:
from core.models import Images, Post
from rest_framework import serializers
class PostSerializer(serializers.ModelSerializer):
images = serializers.SerializerMethodField()
class Meta:
model = Post
fields = '__all__'
def create(self, validated_data):
new_post = Post.objects.create(**validated_data)
data = self.context['request'].data
for key, image in data.items():
if key != 'title' and key != 'body':
image = Images.objects.create(post=new_post, image=image)
return new_post
def get_images(self, obj):
images = []
qs = Images.objects.filter(post=obj)
for item in qs:
images.append(item.image.name)
return images
views.py:
from rest_framework import viewsets
from core.models import Post
from core.serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
TestComponent.vue:
<template>
<div class="container" style="display: flex; justify-content: center; align-items: center;">
<form @submit.prevent="submit" >
<div class="mb-3">
<label for="exampleInputTitle" class="form-label">Title</label>
<input type="text" class="form-control" id="exampleInputTitle" v-model="title">
</div>
<div class="mb-3">
<label for="exampleInputBody" class="form-label">Body</label>
<input type="text" class="form-control" id="exampleInputBody" v-model="body">
</div>
<div class="mb-3">
<label for="formFileMultiple" class="form-label">Multiple files input example</label>
<input class="form-control" type="file" id="formFileMultiple" ref="file" multiple>
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</template>
<script>
import axios from 'axios'
export default {
data () {
this.title = '',
this.body = ''
},
methods: {
submit() {
const formData = new FormData();
for( var i = 0; i < this.$refs.file.files.length; i++ ){
let file = this.$refs.file.files[i];
formData.append('files[' + i + ']', file);
}
formData.append("title", this.title);
formData.append("body", this.body);
axios.post('http://localhost:8000/posts/', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error.response);
});
}
},
mounted() {
axios.get('http://localhost:8000/posts/')
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error.response);
});
}
}
</script>
- [Vuejs]-How to make my side bar to look dynamic when page zoom is growing?
- [Vuejs]-Why the emit of an event is not working with vue, while the logic is completed
0๐
Hope this helps someone.
Finally after three days battling with this I found the solution to my issue. In the models I have this function that generates a string I can use as the upload_to string for the PostImage:
def post_directory_path(instance, filename):
return 'user_{0}/posts/post_{1}/{2}'.format(instance.user.id, instance.post.id, filename)
There is no user instance on the PostImage only on the Post and Django does not not throw an exception or show any errors for this mistake, which is why I did not look for the problem there.