Неправильный путь вместо фактического файла сохраняется в бэкенд в Django
Мы действительно боремся с этим
У меня есть Vue front end с HTML формой
<form id="postForm" method="POST" action="">
<div class="mediaButtons horizontal mb10">
<div class="mediaButton">
<input
type="file"
name=""
id="postImages"
accept="image/jpg, image/png, image/jpeg, image/tiff, image/webp, image/bmp, image/svg"
@change="handleImages"
multiple
maxFileSize="50000"
/>
<div class="buttonImage">
<img class="buttonImg" src="../assets/img/pic.png" />
</div>
</div>
</div>
<fieldset class="postButtons mt20" v-if="catChosen">
<button class="topBtn" type="button" name="addPost" @click="submitPost">
Post
</button>
<button
class="canBtn"
type="button"
name="addPost"
@click="store.hideAddaPost"
>
Cancel
</button>
</fieldset>
</form>
Функция для обработки изображений и их отображения следующая:
import { ref } from "vue";
const fields = ref({
previews: [],
images: [],
});
function handleImages(event) {
var input = event.target;
var count = input.files.length;
function isFileImage(file) {
return file && file["type"].split("/")[0] === "image";
}
if (count > 8) {
return store.messages.push("Max 8 images per post please");
}
for (const file of input.files) {
if (isFileImage(file)) {
} else {
return store.messages.push("Only image files are allowed");
}
}
var index = 0;
while (count--) {
var reader = new FileReader();
reader.onload = (e) => {
fields.value.previews.push(e.target.result);
};
fields.value.images.push(input.files[index]);
reader.readAsDataURL(input.files[index]);
index++;
}
}
Я отправляю данные на бэкэнд с помощью этой функции:
function submitPost() {
let uploaded_images = []
fields.value.images.forEach((val) => uploaded_images.push(val))
const fieldsData = {
"category": selectedCat.value,
"body": fields.value.body,
"can_view": fields.value.audience,
"can_comment": fields.value.cancomment,
"published": true,
"video": fields.value.video,
"user": store.userId,
"uploaded_images": uploaded_images
};
axios
.post("api/v1/posts/create/", fieldsData, {
headers: {
"Content-Type": "multipart/form-data",
"X-CSRFToken": "{{csrf-token}}",
},
})
.then((response) => {
if (response.status == 201) {
store.messages.push("Post created successfully");
}
})
.catch((error) => {
store.messages.push(error.message);
});
}
после отправки данных и файлов я отправляю их на бэкенд фреймворка Django Rest со всем следующим:
views.py
class PostViewSet(viewsets.ModelViewSet):
parser_classes = [MultiPartParser, FormParser]
queryset = Post.objects.all()
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticated]
def get_serializer_context(self):
return {'request': self.request}
serializers.py
class PostImageSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = ["id", "image", "post"]
extra_kwargs = {
"post": {"required": True},
}
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
uploaded_images = serializers.ListField(
required=False,
child=serializers.FileField(
allow_empty_file=False,
),
write_only=True,
)
class Meta:
model = Post
fields = [
"id",
"category",
"body",
"images",
"uploaded_images",
"video",
"can_view",
"can_comment",
"user",
"published",
"pinned",
"created_at",
"updated_at",
]
def create(self, validated_data):
request = self.context.get("request")
new_post = Post.objects.create(**validated_data)
images = request.FILES
if images:
try:
for image in images.getlist('uploaded_images'):
PostImage.objects.create(image=image, post=new_post)
except:
PostImage.objects.create(post=new_post)
return new_post
и models.py
def user_directory_path(instance, filename):
return 'posts/user_{0}/{1}'.format(instance.user.id, filename)
def post_directory_path(instance, filename):
return 'posts/post_{0}/{1}'.format(instance.post.id, filename)
class Post(models.Model):
EV = "Everybody"
FO = "Followers"
FR = "Friends"
AUDIENCE = [
(EV, "Everybody"),
(FO, "Followers"),
(FR, "Friends"),
]
category = models.ForeignKey(Category, on_delete=models.SET_DEFAULT, default=1)
slug = AutoSlugField(populate_from=["category", "created_at", "user"])
body = models.TextField("content", blank=True, null=True, max_length=5000)
video = models.FileField(
upload_to=user_directory_path, null=True, blank=True
)
can_view = models.CharField(max_length=10, choices=AUDIENCE, default=EV)
can_comment = models.CharField(max_length=10, choices=AUDIENCE, default=EV)
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="author")
published = models.BooleanField(default=False)
pinned = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "post"
verbose_name_plural = "posts"
db_table = "posts"
ordering = ["created_at"]
def __str__(self):
return self.body[0:30]
def get_absolute_url(self):
return self.slug
class PostImage(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='images')
image = models.FileField(upload_to="posts/images", default='posts/default.png', null=True)
class Meta:
db_table = "post_images"
ordering = ["post"]
Представленные данные выглядят следующим образом:
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="category"
1
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="body"
post1
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="can_view"
Everybody
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="can_comment"
Everybody
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="published"
true
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="user"
1
-----------------------------153586592122438730432684753649
Content-Disposition: form-data; name="uploaded_images.0"; filename="tumblr_42e2ad7e187aaa1b4c6f4f7e698d03f2_c9a2b230_640.jpg"
Content-Type: image/jpeg
ÿØÿà
После отправки данных создается пост и количество PostImages, равное количеству загруженных мною изображений.
Проблема в том, что когда я пытаюсь посмотреть на одно из изображений, я получаю ошибку:
backend/storage/uploaded_images.2” does not exist
Почему в данных, которые я отправляю обратно, имя файла выглядит как "uploaded_images.0", "uploaded_images.1" и так далее, а не "uploaded_images[0]"?
Почему файлы не сохраняются по пути, который я указал в модели для поля?
Полезная нагрузка запроса явно представляет собой данные, которые не закодированы, это правильный способ отправки данных?