在django rest框架中,我可以使用danialfarid/ng-file-upload
上传单个文件views.py:
class PhotoViewSet(viewsets.ModelViewSet):
serializer_class = PhotoSerializer
parser_classes = (MultiPartParser, FormParser,)
queryset=Photo.objects.all()
def perform_create(self, serializer):
serializer.save(blogs=Blogs.objects.latest('created_at'),
image=self.request.data.get('image'))
serializers.py:
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
models.py:
class Photo(models.Model):
blogs = models.ForeignKey(Blogs, related_name='blogs_img')
image = models.ImageField(upload_to=content_file_name)
当我尝试上传多个文件时。我进去了
chrome开发者工具: 请求有效负载
------WebKitFormBoundaryjOsYUxPLKB1N69Zn
Content-Disposition: form-data; name="image[0]"; filename="datacable.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryjOsYUxPLKB1N69Zn
Content-Disposition: form-data; name="image[1]"; filename="datacable2.jpg"
Content-Type: image/jpeg
响应:
{"image":["No file was submitted."]}
我不知道如何编写用于上传多个文件的序列化程序。任何人都请帮忙。
先谢谢
答案 0 :(得分:15)
我设法解决这个问题,我希望它能帮助社区
serializers.py:
class FileListSerializer ( serializers.Serializer ) :
image = serializers.ListField(
child=serializers.FileField( max_length=100000,
allow_empty_file=False,
use_url=False )
)
def create(self, validated_data):
blogs=Blogs.objects.latest('created_at')
image=validated_data.pop('image')
for img in image:
photo=Photo.objects.create(image=img,blogs=blogs,**validated_data)
return photo
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
read_only_fields = ("blogs",)
views.py:
class PhotoViewSet(viewsets.ModelViewSet):
serializer_class = FileListSerializer
parser_classes = (MultiPartParser, FormParser,)
queryset=Photo.objects.all()
答案 1 :(得分:1)
我不太了解它,但这是有效的...... 这是我的观点。
def perform_create(self, serializer):
obj = serializer.save()
for f in self.request.data.getlist('files'):
mf = MyFile.objects.create(file=f)
obj.files.add(mf)
答案 2 :(得分:0)
花了我一段时间才找到有效的解决方案,
我想与您分享最终对我有用的东西。
我正在使用reactjs
和DRF
。
这是我的模特:
class MediaFile(models.Model):
article = models.ForeignKey(Articles, on_delete=models.CASCADE, null=True)
caption = models.CharField(max_length=500, null=True, blank=True)
file = models.FileField('photo of article', upload_to=set_filename,
blank=True, null=True, default='')
added = models.DateTimeField(auto_now_add=True)
视图是标准的viewsets.ModelViewSet
class MediaFilesViewSet(viewsets.ModelViewSet):
serializer_class = FileListSerializer
parser_classes = (parsers.MultiPartParser, parsers.FormParser,)
queryset=MediaFile.objects.all()
在ArticleSerializer
中,我添加了:
def create(self, validated_data):
request = self.context.get('request')
user = request.user
instance = Articles.objects.create(**validated_data)
instance.publisher = user
instance.save()
images = request.FILES
if images:
try:
for f in images.getlist('mediafiles'):
instance.mediafile_set.get_or_create(file=f, caption=f.name)
instance.save()
except Exception as e:
print(e)
return instance
FRONTEND结构:
postChangeImage = (event) =>{
this.setState({
is_images: true
});
let files = event.target.files;
const files_array = Object.values(files);
this.setState(
{imagefile: files}
);
console.log('IMAGES ARRAY', files_array);
files_array.map(value => {
const urls = URL.createObjectURL(value);
this.setState((prevState)=>(
{postfolio:[urls, ...prevState.postfolio]}
));
});
};
和发布:
for (let i=0; i< this.state.imagefile.length; i++) {
form_data.append(`mediafiles`, this.state.imagefile[i]);
}
答案 3 :(得分:0)
以下是在博客 api 上上传多个文件的方法:
models.py
class Blogs(models.Model):
...
class Photo(models.Model):
blogs = models.ForeignKey(Blogs, related_name='blogs_img')
image = models.ImageField(upload_to=content_file_name)
serializers.py
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
fields = ['blogs', 'image',]
class BlogsSerializer(serializers.ModelSerializer):
photos = serializers.SerializerMethodField()
def get_photos(self, obj):
photos = Photo.objects.filter(blogs=obj)
return PhotoSerializer(photos, many=True, read_only=False).data
class Meta:
model = Blogs
fields = [
...
'photos',
]
views.py
class BlogsViewSet(viewsets.ModelViewSet):
serializer_class = BlogsSerializer
queryset = Blogs.objects.all()
def create(self, request, *args, **kwargs):
instance_data = request.data
data = {key: value for key, value in instance_data.items()}
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
instance = serializer.save()
if request.FILES:
photos = dict((request.FILES).lists()).get('photos', None)
if photos:
for photo in photos:
photo_data = {}
photo_data["blogs"] = instance.pk
photo_data["image"] = photo
photo_serializer = PhotoSerializer(data=photo_data)
photo_serializer.is_valid(raise_exception=True)
photo_serializer.save()
return Response(serializer.data)
答案 4 :(得分:0)
这个问题的最佳答案对我不起作用,但查尔斯的建议非常有效。就我而言,我需要上传多个文件并将它们分配给特定批次。每个批次都分配给一个特定的用户。
以下是使用 ReactJS 发出 POST 请求的更多上下文,以及使用的序列化程序和 Postman 窗口:
api.py
from convert_files.models import File
from rest_framework import viewsets, permissions
from rest_framework.parsers import MultiPartParser, JSONParser
from .serializers import BatchSerializer
class BatchViewSet(viewsets.ModelViewSet):
permission_classes = [
permissions.IsAuthenticated
]
def perform_create(self, serializer):
obj = serializer.save(owner=self.request.user)
for f in self.request.data.getlist('files'):
mf = File.objects.create(office_file=f)
obj.files.add(mf)
parser_classes = (MultiPartParser, JSONParser, )
serializer_class = BatchSerializer
http_method_names = ['get','post','delete','put','patch', 'head']
def get_queryset(self):
return self.request.user.batches.all()
serializers.py
from rest_framework import serializers
from convert_files.models import File, Batch
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields = '__all__'
class BatchSerializer(serializers.ModelSerializer):
files = FileSerializer(many=True, required = False)
class Meta:
model = Batch
fields = '__all__'
models.py
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from .extra import ContentTypeRestrictedFileField
def make_upload_path(instance, filename):
"""Generates upload path for FileField"""
return settings.OFFICE_OUTPUT_FILES_URL + "/%s" % (filename)
class Batch(models.Model):
name = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
date_posted = models.DateTimeField(default=datetime.datetime.now)
owner = models.ForeignKey(User, related_name="batches",
on_delete=models.CASCADE, null=True)
class File(models.Model):
name = models.CharField(max_length=100, blank=True)
office_file = ContentTypeRestrictedFileField(
upload_to = make_upload_path,
content_types = ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel','application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
max_upload_size = 10485760,
)
files = models.ForeignKey(Batch, on_delete=models.CASCADE, null=True,
related_name='files', related_query_name='files')
FileUpload.js
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { addBatch } from '../actions/batches';
function FileUpload() {
const dispatch = useDispatch();
let formData = new FormData()
const onDrop = useCallback((acceptedFiles) => {
for (var i = 0; i < acceptedFiles.length; i++) {
formData.append("files", acceptedFiles[i], acceptedFiles[i].name)
}
dispatch(addBatch(formData));
})
...
邮递员
Image of POST request in Postman for Multiple File Upload to DRF