如何不重复自己(干)

时间:2017-01-16 14:21:48

标签: python django django-views http-authentication

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

我的应用:

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))

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

1 个答案:

答案 0 :(得分:2)

我将跳过关于不重复自己的强制性笑话,但是跟进Utkbansal的评论,您可以创建自己的Mixin类,也可以创建自己的基本视图,两个视图都可以从中获取。即对象继承。也就是说,最简单的(也是我敢说的最好!)方法是通过继承PermissionRequiredMixin

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))