Django REST Framework POST请求405方法不允许问题求助
问题:POST请求创建Track资源时返回405 Method Not Allowed
问题详情
开发类Spotify后端服务时,调用http://127.0.0.1:8000/music/add/接口发送POST请求创建Track资源,服务器返回405 Method Not Allowed错误。
请求示例
POST http://127.0.0.1:8000/music/add/ Content-Type: application/json Authorization: token 3e356c812614c3d4344e0d06773c27387b1e4c12 { "title": "Evil Ways", "duration": "00:03:47", "release_date": "2023-09-03", "audio_file": "/media/tracks/Music_Library.musiclibrary.zip", "artist": 2, "album": 2, "genre": 1 }
服务器响应
HTTP/1.1 405 Method Not Allowed Date: Thu, 08 Feb 2024 09:11:56 GMT Server: WSGIServer/0.2 CPython/3.9.0 Content-Type: application/json Vary: Accept, Cookie Allow: OPTIONS, GET X-Frame-Options: DENY Content-Length: 41 { "detail": "Method \"POST\" not allowed." }
相关代码
music应用的urls.py
from django.urls import path from . import views urlpatterns = [ # path for get requests path('',views.get_all_tracks, name='get_all_tracks'), path('<str:track_name>/', views.get_tracks_by_name, name='get_tracks_by_name'), path('add/', views.add_track), ]
项目根urls.py
from django.contrib import admin from django.urls import path, include from .views import ( home_page, ) urlpatterns = [ path('admin/', admin.site.urls), path('', home_page), path('auth/', include('authentication.urls')), path('music/', include('music.urls')), path('album/', include('album.urls')), path('artist/', include('artist.urls')), path('playlist/', include('playlist.urls')) ]
views.py中的add_track视图
from django.shortcuts import render from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from .models import Track, Artist, Genre, Album from .serializers import TrackSerializer from rest_framework.decorators import api_view, authentication_classes , permission_classes from rest_framework.authentication import SessionAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated # ... other views @api_view(['GET', 'POST']) @authentication_classes([SessionAuthentication, TokenAuthentication]) @permission_classes([IsAuthenticated]) def add_track(request): if request.method =="POST": title = request.data.get('title') artist_id = request.data.get('artist') album_id = request.data.get('album') duration = request.data.get('duration') release_date = request.data.get('release_date') genre_id = request.data.get('genre') audio_file = request.data.get('audio_file') # Create a new Track object track = Track.objects.create( title=title, artist_id=artist_id, album_id=album_id, duration=duration, release_date=release_date, genre_id=genre_id, audio_file=audio_file ) # Return a JSON response with the created track data data = { 'title': track.title, 'artist': track.artist.name, 'album': track.album.title, 'duration': str(track.duration), 'release_date': str(track.release_date), 'genre': track.genre.name, 'audio_file': track.audio_file.url, # Assuming 'audio_file' is a FileField } return JsonResponse(data, status=201) else: return "this page needs a POST request"
models.py中的Track模型
from django.db import models from artist.models import Artist from album.models import Album class Genre(models.Model): name = models.CharField(max_length=100, unique=True) def __str__(self): return self.name class Track(models.Model): title = models.CharField(max_length=200) artist = models.ForeignKey(Artist, on_delete=models.CASCADE) album = models.ForeignKey(Album, on_delete=models.CASCADE) duration = models.DurationField() release_date = models.DateField() genre = models.ForeignKey(Genre, on_delete=models.CASCADE) audio_file = models.FileField(upload_to='tracks/') # Add other track-related fields (e.g., lyrics) def __str__(self): return self.title
解决方案
1. 修复URL路由顺序问题
当前music/urls.py中,动态路由path('<str:track_name>/', ...)会优先匹配music/add/请求(add会被当作track_name参数),导致请求被路由到仅支持GET的get_tracks_by_name视图。调整路由顺序,将更具体的add/路由放在动态路由前面:
urlpatterns = [ path('',views.get_all_tracks, name='get_all_tracks'), path('add/', views.add_track), # 移到动态路由前 path('<str:track_name>/', views.get_tracks_by_name, name='get_tracks_by_name'), ]
2. 修复视图的非POST响应格式
原视图在非POST请求时返回字符串,不符合DRF响应规范,改为返回DRF的Response对象:
from rest_framework.response import Response @api_view(['GET', 'POST']) @authentication_classes([SessionAuthentication, TokenAuthentication]) @permission_classes([IsAuthenticated]) def add_track(request): if request.method =="POST": # 原POST逻辑不变 else: return Response({"detail": "该接口仅支持POST请求"}, status=400)
3. 用序列化器验证数据(推荐)
直接使用request.data.get()创建模型易导致数据错误,建议用DRF序列化器做数据校验:
@api_view(['GET', 'POST']) @authentication_classes([SessionAuthentication, TokenAuthentication]) @permission_classes([IsAuthenticated]) def add_track(request): if request.method =="POST": serializer = TrackSerializer(data=request.data) if serializer.is_valid(): track = serializer.save() data = { 'title': track.title, 'artist': track.artist.name, 'album': track.album.title, 'duration': str(track.duration), 'release_date': str(track.release_date), 'genre': track.genre.name, 'audio_file': track.audio_file.url, } return Response(data, status=201) return Response(serializer.errors, status=400) else: return Response({"detail": "该接口仅支持POST请求"}, status=400)
4. 调整音频文件传递方式(可选)
请求中audio_file字段传递的是本地路径,若为文件上传场景,需改用multipart/form-data格式发送请求,传递实际文件对象而非路径字符串。
内容的提问来源于stack exchange,提问作者Chanakya Sharma
相关产品推荐
相关产品推荐

