我的项目中有一个常规的ModelViewSet
,它可以很好地与GET
和POST
请求一起使用,但是对PUT
却失败,并返回以下错误:>
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
这是我的 urls.py :
from django.urls import path,re_path,include
from django.utils.text import slugify,camel_case_to_spaces
from PaymentsManagerApp import views, models
from rest_framework import routers
APP_NAME = 'PaymentsManagerApp'
router = routers.DefaultRouter()
router.register(r'payments', views.PaymentViewSet)
payments_list = views.PaymentViewSet.as_view({
'get':'list',
'post':'create'
})
payment_detail = views.PaymentViewSet.as_view({
'get':'retrieve',
'put':'update',
'patch':'partial_update',
'delete':'destroy'
})
def urlpattern_from_route(route):
if "regex" in route and route['regex']:
path_method = re_path
else:
path_method = path
return path_method(route['path'],route['view'].as_view(),name=route['name'] if "name" in route else None)
routes_views = list(map(urlpattern_from_route,routes))
route_services = [
payment_detail = views.PaymentViewSet.as_view({
'get':'retrieve',
'put':'update',
'patch':'partial_update',
'delete':'destroy'
})
route_services = [
path('payments/', payments_list, name='rest_payments_list'),
path('payments/<int:pk>/', payment_detail, name='rest_payment_detail'),
]
urlpatterns = routes_views + route_services
这是我的 views.py :
import os
import json
from datetime import datetime, timedelta
from django.shortcuts import render
from PaymentsManagerApp import urls, models, serializers
from FrontEndApp import urls as Fronturls
from django.shortcuts import render,redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.views.generic import View
from django.contrib.auth.models import Permission
from GeneralApp.utils import get_catalogs
from django.contrib.staticfiles import finders
from django.utils.text import slugify,camel_case_to_spaces
from rest_framework import viewsets, permissions
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from rest_framework.filters import OrderingFilter, SearchFilter
from django.db.models import Q
class PaymentViewSet(viewsets.ModelViewSet):
exclude_from_schema = True
permission_classes = (permissions.IsAuthenticated,)
queryset = models.Payment.objects.all()
serializer_class = serializers.PaymentSerializer
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
search_fields = ('payment_type', 'creation_user__username', 'provider__name', 'invoice', 'payment_method_type', 'payment_document_number')
filter_fields = ('id', 'payment_type', 'creation_user', 'provider', 'is_payment_requested', 'is_paid', 'payment_method_type')
当我将GET或POST发送到payments_manager/payments/
时,它可以正常工作。另外,当我将GET发送到pyments_manager/payments/<int:pk>/
时,效果很好。
问题是当我将PUT发送到payments_manager/payments/<int:pk>/
时,因为得到以下信息:
我不知道为什么,但是DRF丢失了登录的用户信息(您可以看到登录标签,而不是用户名)。
编辑
这是我在 settings.py 中的REST_FRAMEWORK:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 20,
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata'
}
编辑
我发现仅当我使用DRF默认界面(127.0.0.1:8000/es/payments_manager/payments/1/
)从浏览器直接访问端点时,错误才会出现:
我的PUT请求可以从我的javascript ajax完美运行。
答案 0 :(得分:0)
为了使用会话身份验证并进行POST
(有点怪异)/ PUT
/ PATCH
/ DELETE
/等等,您必须传递标头
我还为您创建了一个小测试:
response = self.client.post('/session-login/', data={'username': 'user', 'password': 'pass'})
self.assertEqual(302, response.status_code)
self.assertIn('csrftoken', response.cookies)
self.assertIn('sessionid', response.cookies)
# Don't want to go through the trouble of having to get the CSRF from the login form
self.client.handler.enforce_csrf_checks = True
csrftoken = self.client.cookies.get('csrftoken').value
# NOTE: The only reason this works it's because we're passing a header along with the request.
response = self.client.patch('/payments/%s/' % (self.payment.id), content_type='application/json',
data=json.dumps({'is_paid': 'Y'}), HTTP_X_CSRFTOKEN=csrftoken)
self.assertEqual(200, response.status_code)
self.assertEqual('Y', response.json()['is_paid'])
# NOTE: The reason this DOES NOT works it's because we're NOT passing a header along with the request.
response = self.client.patch('/payments/%s/' % (self.payment.id), content_type='application/json',
data=json.dumps({'is_paid': 'N'}))
self.assertEqual(403, response.status_code)
编辑。
添加了一个用户,登录后,导航到localhost/payments/
并添加了一条记录,然后转到记录localhost/payments/1/
并对其进行了更新(PUT
)。一切正常。请添加您的django / drf版本。