URL 查找不适用于更新和检索
URL lookup not working with update and retrieve
在 url /users/*username
我应该能够通过用户名访问每个用户,问题是它没有按预期工作,不管我写什么在 *username
中它将 update/delete 当前登录的用户。
示例:
我可以通过 /users/123/ 更新用户“admin”,即使 123 显然不是 admin 或任何其他现有用户。
这是用户视图,其中的方法未按我的预期方式工作:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
serializer_class = UserSerializer
lookup_field = 'username'
queryset = User.objects.all()
def get_permissions(self):
if self.action in ['signup', 'login',]:
permissions = [AllowAny]
elif self.action in ['retrieve', 'update', 'destroy']:
permissions = [IsAuthenticated, IsSameUser]
else:
permissions = [IsAuthenticated]
return [p() for p in permissions]
def retrieve(self, request, *args, **kwargs):
response = super(UserViewSet, self).retrieve(request, *args, **kwargs)
data = response.data
return Response(data=data, status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
serializer = UserModelSerializer(request.user, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
用户URL:
""" Users URLs """
# Django
from django.urls import include, path
# Django REST Framework
from rest_framework.routers import DefaultRouter
# Views
from users.views import UserViewSet
router = DefaultRouter()
router.register(r'users/', UserViewSet, basename='users')
urlpatterns = [
path('', include(router.urls)),
]
it will update/delete the current logged user.
当然
您的更新方法是:
def update(self, request, *args, **kwargs):
serializer = UserModelSerializer(request.user, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
其中 request.user
是登录用户。
正确的代码是这样的:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
serializer_class = UserSerializer
lookup_field = 'username'
queryset = User.objects.all()
...
def update(self, url_username, request, *args, **kwargs):
try:
user_object = self.queryset.get(username=url_username)
except User.DoesNotExist:
Response({'error': 'not found'}, status=404)
serializer = UserModelSerializer(user_object, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
还需要在URL路径中添加url_username
:
urlpatterns = [
...,
path('users/<str:url_username>', update_user)
]
这里
user_object
是您要更新的用户
request.data
是要设置给现有用户的新数据
url_username
是 /users/*username
中的 *username
部分,用于获取准确的用户
更新 1:回答问题 →
I'm using DRF default router (updated the post and added what my
urls.py looks like), the URL is generated taking the actions from the
viewset, should I make all the URL like you did there? Like it says in
the documentation all the URL patterns should be done automatically.
Oohhh...Django 有数百万种方法来实现 API 方法。根据一段代码在我的脑海中重现行为是非常复杂的。我的答案的关键是你应该使用 username
放在 url 而不是 request.user
中。因为 request.user
是登录用户对象(执行请求的用户)。
首先,试着理解UpdateModelMixin
此 Mixin
提供了正确且标准的 update()
方法。
您试图通过包含 mixins.UpdateModelMixin
并在之后创建(覆盖)自己的 update()
来添加标准 update()
方法。所以包含 UpdateModelMixin
是没用的。
如果您想使用标准 update
方法,只需完全删除自己的 def update():
。这可能是解决方案。
如果要创建自定义 update
方法,请删除 UpdateModelMixin
。没必要。
在这种情况下尝试更改更新参数,例如:
def update(self, request, pk, *args, **kwargs):
try:
user_object = self.queryset.get(username=pk)
...
在你的情况下 pk
将是 username
(因为你设置了 lookup_field = 'username'
)
正如我之前所说,很难预测 Django 的行为(实际上我不记得详细的工作原理 pk
)。试试看会发生什么。
如果 pk
如我所料,您不需要编辑 urlpatterns
。
PS def retrieve(self, request, *args, **kwargs):
如果你包括 RetreiveModelMixin
也是不必要的。 RetreiveModelMixin
为您添加 retrieve()
方法。
在你的 UserSerializer 序列化器中,你应该添加这个元 class:
class Meta:
lookup_field = 'username'
在 url /users/*username
我应该能够通过用户名访问每个用户,问题是它没有按预期工作,不管我写什么在 *username
中它将 update/delete 当前登录的用户。
示例: 我可以通过 /users/123/ 更新用户“admin”,即使 123 显然不是 admin 或任何其他现有用户。
这是用户视图,其中的方法未按我的预期方式工作:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
serializer_class = UserSerializer
lookup_field = 'username'
queryset = User.objects.all()
def get_permissions(self):
if self.action in ['signup', 'login',]:
permissions = [AllowAny]
elif self.action in ['retrieve', 'update', 'destroy']:
permissions = [IsAuthenticated, IsSameUser]
else:
permissions = [IsAuthenticated]
return [p() for p in permissions]
def retrieve(self, request, *args, **kwargs):
response = super(UserViewSet, self).retrieve(request, *args, **kwargs)
data = response.data
return Response(data=data, status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
serializer = UserModelSerializer(request.user, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
用户URL:
""" Users URLs """
# Django
from django.urls import include, path
# Django REST Framework
from rest_framework.routers import DefaultRouter
# Views
from users.views import UserViewSet
router = DefaultRouter()
router.register(r'users/', UserViewSet, basename='users')
urlpatterns = [
path('', include(router.urls)),
]
it will update/delete the current logged user.
当然
您的更新方法是:
def update(self, request, *args, **kwargs):
serializer = UserModelSerializer(request.user, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
其中 request.user
是登录用户。
正确的代码是这样的:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
serializer_class = UserSerializer
lookup_field = 'username'
queryset = User.objects.all()
...
def update(self, url_username, request, *args, **kwargs):
try:
user_object = self.queryset.get(username=url_username)
except User.DoesNotExist:
Response({'error': 'not found'}, status=404)
serializer = UserModelSerializer(user_object, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
还需要在URL路径中添加url_username
:
urlpatterns = [
...,
path('users/<str:url_username>', update_user)
]
这里
user_object
是您要更新的用户request.data
是要设置给现有用户的新数据url_username
是/users/*username
中的*username
部分,用于获取准确的用户
更新 1:回答问题 →
I'm using DRF default router (updated the post and added what my urls.py looks like), the URL is generated taking the actions from the viewset, should I make all the URL like you did there? Like it says in the documentation all the URL patterns should be done automatically.
Oohhh...Django 有数百万种方法来实现 API 方法。根据一段代码在我的脑海中重现行为是非常复杂的。我的答案的关键是你应该使用 username
放在 url 而不是 request.user
中。因为 request.user
是登录用户对象(执行请求的用户)。
首先,试着理解UpdateModelMixin
此 Mixin
提供了正确且标准的 update()
方法。
您试图通过包含 mixins.UpdateModelMixin
并在之后创建(覆盖)自己的 update()
来添加标准 update()
方法。所以包含 UpdateModelMixin
是没用的。
如果您想使用标准 update
方法,只需完全删除自己的 def update():
。这可能是解决方案。
如果要创建自定义 update
方法,请删除 UpdateModelMixin
。没必要。
在这种情况下尝试更改更新参数,例如:
def update(self, request, pk, *args, **kwargs):
try:
user_object = self.queryset.get(username=pk)
...
在你的情况下 pk
将是 username
(因为你设置了 lookup_field = 'username'
)
正如我之前所说,很难预测 Django 的行为(实际上我不记得详细的工作原理 pk
)。试试看会发生什么。
如果 pk
如我所料,您不需要编辑 urlpatterns
。
PS def retrieve(self, request, *args, **kwargs):
如果你包括 RetreiveModelMixin
也是不必要的。 RetreiveModelMixin
为您添加 retrieve()
方法。
在你的 UserSerializer 序列化器中,你应该添加这个元 class:
class Meta:
lookup_field = 'username'