Должны ли authentication_classes и permission_classes в представлениях Django REST Framework быть определены с помощью списков или кортежей?
Я пытаюсь понять, как лучше всего задавать authentication_classes и permission_classes в APIView Django REST Framework. В частности, я видел, что для определения этих атрибутов используются как кортежи, так и списки:
Использование кортежа:
class Home(APIView):
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
Использование списка:
class Home(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [permissions.IsAuthenticated]
Похоже, оба подхода работают корректно, но я не уверен, что есть какие-то конкретные причины предпочесть один из них другому. Следует ли мне использовать список или кортеж в этом сценарии? Есть ли какие-либо последствия использования одного или другого с точки зрения производительности, читабельности или следования лучшим практикам Django REST Framework?
Я пробовал использовать как кортежи, так и списки для authentication_classes и permission_classes в APIView Django REST Framework. Оба варианта работают хорошо, но я не уверен, какой из них лучше или рекомендуется. Я ожидал найти четкое руководство по этому вопросу.
Оба варианта работают эквивалентно. Документация Django REST Framework, похоже, предпочитает списки, так что, возможно, следует использовать списки.
class ListUsers(APIView):
authentication_classes = [authentication.TokenAuthentication]
permission_classes = [permissions.IsAdminUser]
Сначала я объясню процесс выполнения аутентификации в DRF.
class APIView(View):
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
Функцией, которая фактически выполняет аутентификацию в DRF, является функция perform_authentication, но до этого, когда метод initialize_request создает объект запроса, он вызывает метод get_authenticators и передает его в качестве аргумента.
class APIView(View):
...
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
...
Здесь функция get_authenticators повторяет переменную authentication_classes, определенную в View, созданной пользователями, чтобы создать и вернуть каждый объект класса аутентификации.
В этом процессе используется переменная authentication_classes, определенная вопрошающим.
Как видно из приведенного выше кода, это должен быть повторяющийся объект, поскольку он используется в операторе for. Вот почему разрешены упорядочивания и кортежи.
Проверка разрешения одинакова.
class APIView(View):
def dispatch(self, request, *args, **kwargs):
...
try:
self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
...
self.check_permissions(request)
...
def check_permissions(self, request):
for permission in self.get_permissions():
if not permission.has_permission(request, self):
...
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
return [permission() for permission in self.permission_classes]
Процесс проверки разрешений в DRF APIView выглядит следующим образом.
Значение permissions_classes, установленное пользователем, используется в методе get_permissions и выполняет тот же процесс аутентификации, что и ранее.
То есть, поскольку permissions_classes или authentication_classes должны использоваться в повторениях, именно поэтому вы должны использовать массив или кортеж этих проблемных типов данных.
Причина, по которой DRF реализовала вышеуказанную логику для разрешений и аутентификации, заключается в возможности использования множественной аутентификации и разрешений.
Сразу к делу: работают как tuple
, так и list
. В принципе, если вы хотите изменить переменную, то используйте списки. Если вы конкретно не хотите и не желаете, чтобы кто-то изменял переменную, то используйте кортежи. Это просто проблема неизменяемости против изменяемости.