如何使用Axios和react hook形式上传文件到Django rest框架API ?



我使用Django Rest框架创建了一个API。它有一个图片上传选项。但是我无法上传文件。我使用Axios进行API调用,并使用react hook form进行表单处理。我把代码贴在下面,以便更好地理解。

Django: 模型:

class BlogModel(models.Model):
user = models.ForeignKey(user_model.User, on_delete=models.CASCADE, related_name="user_blog")
blogtitle = models.CharField(max_length=250)
blogcontent = models.TextField()
blogimg = models.ImageField(upload_to="blog_image", blank=True)
slug = models.SlugField(max_length=250, unique=True)
tags = models.ManyToManyField(BlogTagsModel, related_name='blog_tags', blank=True, null=True)
published_date = models.DateTimeField(auto_now_add=True)
edit_date = models.DateTimeField(auto_now=True)

序列化器

class BlogSerializer(serializers.ModelSerializer):
class Meta:
model = blog_model.BlogModel
fields = '__all__'
extra_kwargs = {
'user': {'read_only': True},
'slug': {'read_only': True},
}
<<p>视图/em>
class BlogPostView(generics.ListCreateAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
serializer_class = blog_ser.BlogSerializer
queryset = blog_model.BlogModel.objects.all()
def perform_create(self, serializer):
rand_num = random.randint(99, 222)
blog_slug_str = f"{serializer.validated_data.get('blogtitle')}{rand_num}"
sample_string_bytes = blog_slug_str.encode("ascii")
base64_bytes = base64.b64encode(sample_string_bytes)
slug = base64_bytes.decode("ascii")
serializer.save(user=self.request.user, slug=slug)

反应:

形式JSX

<form className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit(onSubmit)}>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="title"
>
Title
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id="title"
type="text"
{...register('title', { required: true })}
/>
{errors.title && <p className="text-red-500 text-xs italic">Title is required</p>}
</div>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="image"
>
Image
</label>
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id="image"
type="file"
{...register('image', { required: true })}
/>
{errors.image && <p className="text-red-500 text-xs italic">Image is required</p>}
</div>
<div className="mb-4">
<label
className="block text-gray-700 text-sm font-bold mb-2"
htmlFor="details"
>
Details
</label>
<textarea
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id="details"
{...register('details', { required: true })}
/>
{errors.details && <p className="text-red-500 text-xs italic">Details is required</p>}
</div>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
type="submit"
>
Submit
</button>
</form>

Axios叫

const onSubmit = data => {
console.log(data.image['0']);
const payload = {
blogtitle: data.title,
blogcontent: data.details,
blogimg: data.image,
}
console.log(payload);
myAxios.post('/api/post/', payload).then(res => {
console.log(res);
}).catch(err => {
console.log(err.response.data);
})
}

当我提交表单时,错误显示为The submitted data was not a file. Check the encoding type on the form..

在安慰有效载荷时,我得到:

{
"blogtitle": "nok",
"blogcontent": "asasa",
"blogimg": {
"0": {}
}
}

Please Help Me…

我找到解决办法了。

原来我必须添加一个标题'Content-Type': 'multipart/form-data'到Axios请求。

我把更新后的代码贴在下面:

Axios叫

const onSubmit = data => {
const payload = {
blogtitle: data.title,
blogcontent: data.details,
blogimg: data.image['0'],
}
console.log(payload);
myAxios.post('/api/post/', payload, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err.response.data);
})
}

最新更新