【问题标题】:How to implement password change in Django Rest Framework without repeating code (DRY principle)如何在不重复代码的情况下在 Django Rest Framework 中实现密码更改(DRY 原理)
【发布时间】:2021-03-28 01:40:17
【问题描述】:

我有一个 Django 应用程序,它已经有一个用于更改密码的 Web 界面。它使用django.contrib.auth 函数和django.views.generic.UpdateView。代码如下:

class PasswordChangeView(LoginRequiredMixin, generic.UpdateView):
    form_class = PasswordChangeForm
    template_name = 'form.html'
    input_value = 'update password'

    def post(self, request, *args, **kwargs):
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # Important!
            try:
                request.user.auth_token.delete()  # Important!
            except (AttributeError, ObjectDoesNotExist):
                pass
            messages.success(request, 'Your password was successfully updated!')
            return redirect('/')
        else:
            messages.error(request, 'Please correct the error below.')

    def get(self, request, **kwargs):
        form = PasswordChangeForm(request.user)
        return render(request, self.template_name, {'form': form, 'input_value': self.input_value})

以上代码在 Web 界面中运行良好。现在我想实现 REST API 来更改密码。我知道我可以创建APIView/viewsetserializer 来做到这一点(就像this 问题的答案),但它会违反DRY 原则。鉴于已经有一个功能齐全的 Web 界面,实现 REST API 界面的最佳方式是什么?

【问题讨论】:

    标签: python django django-rest-framework django-views


    【解决方案1】:

    为 API 实现 Django rest 框架和标准 Django web 视图有点不同。 我建议你为这些创建不同的端点。

    【讨论】:

      【解决方案2】:

      我已经将更改密码的通用部分封装在一个名为update_user_after_password_change 的函数中,这样它就可以在viewviewset 中使用。然后我最终使用了以下代码结构。

      在views.py中:

      class PasswordChangeView(LoginRequiredMixin,
                               generic.UpdateView):
          form_class = PasswordChangeForm
          template_name = 'form.html'
          input_value = 'update password'
      
          def post(self, request, *args, **kwargs):
              form = PasswordChangeForm(request.user, request.POST)
              if form.is_valid():
                  user = form.save()
                  update_user_after_password_change(request, user)
                  messages.success(request, 'Your password was successfully updated!')
                  return redirect('/')
              else:
                  messages.error(request, 'Please correct the error below.')
      
          def get(self, request, **kwargs):
              form = PasswordChangeForm(request.user)
              return render(request, self.template_name, {'form': form, 'input_value': self.input_value})
      
      
      class PasswordChangeViewSet(mixins.UpdateModelMixin,
                                  viewsets.GenericViewSet):
          permission_classes = [IsAuthenticated]
      
          def get_object(self):
              user = self.request.user
              return user
      
          def update(self, request, *args, **kwargs):
              user = self.get_object()
              serializer = serializers.PasswordChangeSerializer(data=request.data)
      
              if serializer.is_valid():
                  old_password = serializer.data.get('old_password')
                  if not user.check_password(old_password):
                      return Response({'old_password': ['Wrong password.']},
                                      status=status.HTTP_400_BAD_REQUEST)
      
                  user.set_password(serializer.data.get('new_password'))
                  user.save()
                  update_user_after_password_change(request, user)
                  return Response(status=status.HTTP_204_NO_CONTENT)
      
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
      
      def update_user_after_password_change(request, user):
          update_session_auth_hash(request, user)
          if hasattr(user, 'auth_token'):
              user.auth_token.delete()
      

      在 serializers.py 中:

      class PasswordChangeSerializer(serializers.Serializer):
          old_password = serializers.CharField(required=True)
          new_password = serializers.CharField(required=True)
      
          def validate_new_password(self, value):
              validate_password(value)
              return value
      

      使用this 可能有更好的方法,但我不知道如何继续。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-03
        • 1970-01-01
        • 2016-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多