You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django和DRF中使用Serializer与Generic View实现用户删除功能,并对现有用户CRUD代码进行安全性与正确性评审

Implementing User Deletion via API

To add user deletion functionality, you have two secure options depending on your needs:

Option 1: Delete own account without PK (most secure)

This lets users delete only their own account without exposing user IDs in the URL:

Add to views.py:

from rest_framework import status
from rest_framework.exceptions import PermissionDenied

class UserDeleteView(APIView):
    permission_classes = (IsAuthenticated,)

    def delete(self, request):
        request.user.delete()
        return Response(
            {"message": "User account deleted successfully"},
            status=status.HTTP_204_NO_CONTENT
        )

Add to urls.py:

path('delete/', UserDeleteView.as_view(), name='delete_user'),

Option 2: Delete by PK (with permission checks)

If you need to support admin-level deletion or explicit PK targeting (but still restrict users to their own account):

Add to views.py:

class UserDeleteView(generics.DestroyAPIView):
    permission_classes = (IsAuthenticated,)
    User = get_user_model()

    def get_object(self):
        user_obj = self.User.objects.get(pk=self.kwargs['pk'])
        if user_obj != self.request.user:
            raise PermissionDenied("You can only delete your own account.")
        return user_obj

Add to urls.py:

path('delete/<int:pk>/', UserDeleteView.as_view(), name='delete_user'),

Code Review & Improvements

Let’s walk through your code to fix security gaps, reduce redundancy, and follow Django/DRF best practices:

1. Serializers.py

UserSerializer:

  • Remove redundant write_only=True for password (set once in field definition or extra_kwargs, not both)
  • Use get_user_model() instead of direct User import for flexibility (critical if using custom user models)
  • Simplify create() method with Django’s built-in create_user():
    from django.contrib.auth import get_user_model
    User = get_user_model()
    
    class UserSerializer(serializers.ModelSerializer):
        password = serializers.CharField(
            max_length=128,
            min_length=8,
            write_only=True
        )
        class Meta:
            model = User
            fields = ('email', 'password', 'first_name', 'last_name')
            extra_kwargs = {
                'first_name': {'required': True},
                'last_name': {'required': True},
            }
        def create(self, validated_data):
            return User.objects.create_user(**validated_data)
    

UpdateUserSerializer:

  • Move permission checks to the view (serializers should handle data validation, not access control)
  • Simplify update() using parent class method:
    class UpdateUserSerializer(serializers.ModelSerializer):
        email = serializers.EmailField(required=True)
        class Meta:
            model = User
            fields = ('first_name', 'last_name', 'email')
            extra_kwargs = {
                'first_name': {'required': True},
                'last_name': {'required': True},
            }
        def validate_email(self, value):
            user = self.context['request'].user
            if User.objects.exclude(pk=user.pk).filter(email=value).exists():
                raise serializers.ValidationError({"email": "This email is already in use."})
            return value
        def update(self, instance, validated_data):
            return super().update(instance, validated_data)
    

Missing ChangePasswordSerializer:
Add this to your serializers (you imported it but didn’t include it):

class ChangePasswordSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True, required=True, min_length=8)
    password2 = serializers.CharField(write_only=True, required=True)
    old_password = serializers.CharField(write_only=True, required=True)

    class Meta:
        model = User
        fields = ('old_password', 'password', 'password2')

    def validate(self, attrs):
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError({"password": "Password fields don't match."})
        return attrs

    def validate_old_password(self, value):
        user = self.context['request'].user
        if not user.check_password(value):
            raise serializers.ValidationError({"old_password": "Old password is incorrect."})
        return value

    def update(self, instance, validated_data):
        instance.set_password(validated_data['password'])
        instance.save()
        return instance

2. Views.py

Critical Security Fix: Your current UpdateUserView and ChangePasswordView allow authenticated users to modify any user’s data if they know the PK. Fix this by restricting access to the current user:

class UpdateUserView(generics.UpdateAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = UpdateUserSerializer

    def get_object(self):
        return self.request.user

class ChangePasswordView(generics.UpdateAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = ChangePasswordSerializer

    def get_object(self):
        return self.request.user

3. Urls.py

Update URLs to remove PK requirements (since views now target the current user):

urlpatterns = [
    path('create/', UserCreate.as_view(), name='user_create'),
    path('token/', views.TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', views.TokenRefreshView.as_view(), name='token_refresh'),
    path('hello/', HelloView.as_view(), name='hello'),
    path('update/', UpdateUserView.as_view(), name='update_user'),
    path('change_password/', ChangePasswordView.as_view(), name='auth_change_password'),
    path('delete/', UserDeleteView.as_view(), name='delete_user'), # Add this
]

Additional Security Best Practices

  • Rate Limiting: Add throttling to login/password endpoints to prevent brute-force attacks (use DRF’s built-in throttle_classes or django-ratelimit)
  • Password Strength: Add validation for uppercase letters, numbers, and special characters in UserSerializer
  • Email Verification: Implement email confirmation for new users to verify ownership
  • HTTPS: Always use HTTPS in production to protect tokens and sensitive data
  • Admin Controls: For admin-level user management, create separate views with IsAdminUser permission

内容的提问来源于stack exchange,提问作者Rashid Kalwar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 12:12:31