如何不重复自己(干)

How to Don't Repeat Yourself (DRY)

我在我的代码中有两个地方有基本授权。我想把它作为一个功能分开,而不是重复代码。

我的应用程序:

from django.shortcuts import render
from django.views.generic import View
from django.http import HttpResponse, Http404
from django.contrib.auth import authenticate
from django.core.exceptions import PermissionDenied
import base64

from notes.models import Note, load_initial_data


class NoteListView(View):



    def filter_queryset(self, query_set):
        query_params = self.request.GET
        if 'board' in query_params:
            query_set = query_set.filter(board=query_params['board'])
        return query_set

    def get(self, request):
        load_initial_data()
        query_set = self.filter_queryset(Note.objects.all())
        basic_auth = True
        # this lines below !
        if basic_auth:
            if 'HTTP_AUTHORIZATION' in request.META:
                auth = request.META['HTTP_AUTHORIZATION'].split()
                if len(auth) == 2:
                    if auth[0].lower() == "basic":
                        uname, passwd = base64.b64decode(auth[1]).split(':')
                        user = authenticate(username=uname, password=passwd)
                        if user is not None and user.is_active:
                            request.user = user
                            if not request.user.is_staff:
                                raise PermissionDenied
                            return HttpResponse(query_set)

            response = HttpResponse()
            response.status_code = 401
            response['WWW-Authenticate'] = 'Basic realm="%s"' % "Basic Auth Protected"
            return response
        else:
            return HttpResponse(query_set)



class NoteView(View):

    def get_object(self, obj_id):
        try:
            return Note.objects.get(id=int(obj_id))
        except IndexError:
            raise Http404

    def get(self, request, note_id):
        load_initial_data()
        basic_auth = True
        #this lines below
        if basic_auth:
            if 'HTTP_AUTHORIZATION' in request.META:
                auth = request.META['HTTP_AUTHORIZATION'].split()
                if len(auth) == 2:
                    if auth[0].lower() == "basic":
                        uname, passwd = base64.b64decode(auth[1]).split(':')
                        user = authenticate(username=uname, password=passwd)
                        if user is not None and user.is_active:
                            request.user = user

                            return HttpResponse(self.get_object(note_id))

            response = HttpResponse()
            response.status_code = 401
            response['WWW-Authenticate'] = 'Basic realm="%s"' % "Basic Auth Protected"
            return response
        else:
            return HttpResponse(self.get_object(note_id))

我在 class NoteListView 的 get func 和 class NoteView 中重复代码。我不知道如何分离这个功能。我用注释标记了重复的行。有什么建议吗?

我会跳过关于不重复自己的强制性笑话,但是根据 Utkbansal 的评论,您可以创建自己的 Mixin class 或创建自己的基础视图,这两个视图都从中派生。即,对象继承。就是说,最简单(我敢说最奇特!)的方法是通过 class 对 PermissionRequiredMixin:

进行子class
from django.contrib.auth.mixins import PermissionRequiredMixin

class BasicAuthRequired(PermissionRequiredMixin):
    def __init__(self):
        super(BasicAuthRequired, self).__init__()
        self.basic_auth = True

    def has_permission(self):
        if self.basic_auth:
            if 'HTTP_AUTHORIZATION' not in request.META:
                return False
            auth = request.META['HTTP_AUTHORIZATION'].split()
            if len(auth) != 2 or auth[0].lower() != "basic":
                return False
            uname, passwd = base64.b64decode(auth[1]).split(':')
            user = authenticate(username=uname, password=passwd)
            if not user or not user.is_active:
                return False
            self.request.user = user # from `View`
            return user.is_staff
        return True # some other type of auth

现在在您看来,您可以执行以下操作,我们可以确信基本身份验证已得到验证并得到妥善处理,并且只处理正面案例:

class NoteView(BasicAuthRequired, View):
    def get_object(self, obj_id):
        try:
            return Note.objects.get(id=int(obj_id))
        except IndexError:
            raise Http404

    def get(self, request, note_id):
        load_initial_data()   
        return HttpResponse(self.get_object(note_id))