Тесты для имен представлений не работают после обновления до Django 4.0

В проекте Django у меня есть тесты, которые проверяют, что URL использует определенное представление на основе класса. Например, у меня есть такое представление:

from django.views.generic import TemplateView

class HomeView(TemplateView):
    template_name = "home.html"

А этот тест:

from django.test import TestCase
from django.urls import resolve
from myapp import views

class UrlsTestCase(TestCase):

    def test_home_view(self):
        self.assertEqual(resolve("/").func.__name__, views.HomeView.__name__)

Этот тест проходит в Django 3.x, но когда я пробую его с Django 4.0, тест не проходит:

self.assertEqual(resolve("/").func.__name__, views.HomeView.__name__)
AssertionError: 'view' != 'HomeView'
- view
+ HomeView

Очевидно, что-то изменилось в Django 4.0, но я не вижу ничего связанного с этим в примечаниях к релизу.

Итак, что изменилось и как я могу заставить этот тест работать снова (или как я могу проверить это лучшим способом)?

Вы используете .as_view(), таким образом возвращается не объект класса, а функция, которая будет обрабатывать запросы, создавая новый HomeView и вызывая соответствующий метод на основе HTTP-метода.

Вы можете проверить, является ли это методом класса HomeView, проверив атрибут .view_class. Кроме того, вероятно, лучше проверять, одинаковы ли два класса, а не имена этих классов:

#                                            ↓ no .__name__  ↓
self.assertEqual(resolve('/').func.view_class, views.HomeView)

Я провел небольшое исследование, почему сравнение __name__ больше не работает. Очевидно, в они использовали update_wrapper(…) функцию , которая устанавливает __name__, __qualname__ и т.д. одного объекта (в данном случае класса) в функцию. Действительно, в исходном коде [GitHub] мы можем увидеть:

@classonlymethod
def as_view(cls, **initkwargs):
    # …
    def view(request, *args, **kwargs):
        # …
    # …

    # take name and docstring from class
    update_wrapper(view, cls, updated=())
    # …

это было изменено в , где они также объяснили в комментарии, почему они больше не делают этого [GitHub]:

@classonlymethod
def as_view(cls, **initkwargs):
    # …
    # __name__ and __qualname__ are intentionally left unchanged as
    # view_class should be used to robustly determine the name of the view
    # instead.
    # …
Вернуться на верх