使用axios向Django制作的API发出Put请求会导致500内部服务器错误
经历
当对由Django Rest Framework创建的API执行PUT操作时,会显示500(内部服务器错误)。
总结原因和解决方法。
设计
.
├── README.rst
├── apiv1
│ ├── __init__.py
│ ├── __pycache__
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── config
│ ├── __init__.py
│ ├── __pycache__
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
├── env
│ ├── bin
│ ├── include
│ ├── lib
│ └── pyvenv.cfg
├── manage.py
├── memo.txt
├── vue
│ ├── index.html
│ ├── style.css
│ └── vue_script.js
└── woop # Django models作成用
├── __init__.py
├── __pycache__
├── admin.py
├── apps.py
├── migrations
├── models.py
├── tests.py
└── views.py
后端 Django rest framework
from django.db import models
from django.utils import timezone
# Create your models here.
import uuid
class Goal(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(verbose_name='目標', max_length=40)
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
from rest_framework import serializers
# models
from woop.models import Goal, Task
class GoalSerializer(serializers.ModelSerializer):
class Meta:
model = Goal
fields = ['id', 'title', 'created_at']
from django.shortcuts import render
from rest_framework import viewsets
from woop.models import Goal, Task
from .serializers import GoalSerializer, TaskSerializer
class GoalViewSet(viewsets.ModelViewSet):
queryset = Goal.objects.all()
serializer_class = GoalSerializer
前端 Vue(CDN)
我们在Vue中使用了CDN。这包括index.html文件、Vue的js文件以及css文件这三个部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<input v-model='new_goal'>
<button v-on:click='postGoal(new_goal)' class='btn'>登録</button>
<p>目標の数 : {{ goals.length }}</p>
<ul>
<li v-for='(goal, index) in goals' v-bind:key='goal.id'>
<div style='font-size: 5px;'>id : {{ goal.id }}</div>
<div v-if='!isEditGoal' v-on:dblclick='isEditGoal = true'>
{{ index }}: {{ goal.title }}</div>
<div v-else><input type='text' v-model='goal.title' v-on:blur='updateGoal(goal.id, goal.title)'></div>
<div style='font-size: 5px;'>{{ goal.created_at }}</div>
<button v-on:click='deleteGoal(goal.id)' class='btn'>削除</button>
</li>
</ul>
<pre>{{ $data }}</pre>
</div>
</div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src='/vue/vue_script.js'></script>
</body>
</html>
new Vue({
el: '#app',
data: function (){
return {
goals: {},
new_goal: '',
isEditGoal: false,
}
},
created() {
this.reloadGoal();
},
methods: {
postGoal: function (title) {
const vm = this;
axios.post('http://127.0.0.1:8000/api/v1/Goal/',
{ title: title })
.then(response => { vm.reloadGoal(); })
},
deleteGoal: function (id) {
const vm = this;
axios.delete('http://127.0.0.1:8000/api/v1/Goal/' + id)
.then(response => { vm.reloadGoal(); })
},
updateGoal: function (id, title) {
const vm = this;
console.log(vm)
axios.put('http://127.0.0.1:8000/api/v1/Goal/' + id,
{ id: id, title: title })
.then(response => { vm.isEditGoal = false })
.catch((error) =>{ console.log(error) })
.then(response => { vm.reloadGoal(); })
},
reloadGoal() {
const vm = this;
axios.get('http://127.0.0.1:8000/api/v1/Goal/')
.then((response) => { vm.goals = response.data })
},
},
}
)
这段代码的输出如下所示。
每个目标都被注册了,并且显示了id、title和created_id。
如果双击标题部分,它会切换到input元素(通过切换isEditGoal的值为false和true),以便可以更新内容。
点击输入表单的边框部分,或者使用Tab键切换到表单上的其他元素,以确认更新的内容,并返回到文本。
spread.js:25 PUT http://127.0.0.1:8000/api/v1/Goal/3932e94a-1894-445e-ba2b-4415899fa2a8 500 (Internal Server Error)
Error: Request failed with status code 500
at e.exports (spread.js:25)
at e.exports (spread.js:25)
at XMLHttpRequest.l.onreadystatechange (spread.js:25)
根据上述所述的错误。
当查询状态码为500时,会显示服务器错误,因此可能是Django端出现了问题。
原因的确认方法 de
当我使用诸如axios状态码500、vue put等关键词进行搜索时,我找到了一个关于相同情况的问题。
错误:请求失败,状态码为500#1989。
在上述问题中,这不是axios的问题,而是后端存在问题。由于开发者工具的网络提示请您查看有问题的部分,所以我决定去看一下。
错误
您通过PUT方法调用了这个URL,但URL未以斜杠结尾且您已经设置了APPEND_SLASH。Django无法在保留PUT数据的同时重定向到斜杠结尾的URL。请将您的表单更改为指向 127.0.0.1:8000/api/v1/Goal/0c08d6b1-03cf-47f8-979e-60cb53704f52/(注意末尾的斜杠),或在Django设置中将APPEND_SLASH设置为False。
由于调用的URL末尾没有斜杠,因此我想要进行重定向。然而,Django无法在重定向时保持PUT数据不变,所以请修改设置。
如果Django的末尾没有斜杠,且settings.py中的APPEND_SLASH为True时,它会进行重定向。(默认值为True)
解决方案
我先在用Vue定义的`updateGoal`方法中的axios.put的第一个参数上添加了`+ ‘/’`。
updateGoal: function (id, title) {
const vm = this;
console.log(vm)
axios.put('http://127.0.0.1:8000/api/v1/Goal/' + id + '/',
{ id: id, title: title })
.then(response => { vm.isEditGoal = false })
.catch((error) =>{ console.log(error) })
.then(response => { vm.reloadGoal(); })
},