Django FormView и ListView ошибка множественного наследования

Проблема

У меня есть AccesCheck Mixin, и представление с именем ListFormView, которое наследует AccessCheck, FormView и ListView для отображения списка и создания/обновления объектов Worker. Но когда я пытаюсь добавить новые данные методом POST, django продолжает возвращать Attribute Error : Worker object has no attribute 'object_list' ошибку.

Что еще больше меня смущает, так это то, что весь ListFormView дублирует другой вид, основанный на классе, который используется в другом приложении, а оригинальный вид работает без проблем. Я дважды проверил все свои коды и все еще не знаю, как решить эту проблему.

[AccessCheck]

class AccessCheck(LoginRequiredMixin, UserPassesTestMixin, View):
    def test_func(self, *args, **kwargs):
        access = [x.id for x in Auth.objects.filter(auth_id = self.kwargs['target'])]
        return self.request.user.is_superuser or selr.request.user.id in access

    def handle_no_permission(self):
        return redirect('index')

    get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['shop'] = Shop.objects.get(shop_id = self.kwars['shop_id'])
        return context

[ListFormView]

class Worker(AccessCheck, FormView, ListView):
    template_name = 'my_template_name.html'
    context_object_name = 'workers'
    form_class = WorkerForm
    success_url = './my_url'

    def form_valid(self, form):
        data = form.save()
        return super().form_valid(form)

    def get_queryset(self, *args, **kwargs):
        return Worker.objects.filter(shop_id = self.kwargs['shop_id'])

Множественное наследование - богатый источник ошибок, если вы не сделаете все, кроме последнего суперкласса, классом Mixin (производным от object). Я бы предложил

class AccessCheckMixin(LoginRequiredMixin, UserPassesTestMixin):
    # merging two mixins and adding methods is fine
    def test_func(self, *args, **kwargs):
        access = [x.id for x in Auth.objects.filter(auth_id = self.kwargs['target'])]
        return self.request.user.is_superuser or selr.request.user.id in access

    def handle_no_permission(self):
        return redirect('index')

    # get_context_data belongs in a View subclass

class ListFormView(AccessCheckMixin, FormView, ListView):
    # I have misgivings about merging FormView and ListView, but maybe 
    ...
    def get_context_data(self, **kwargs):
        # it belongs here, but super() is going to invoke only one of the
        # get_context_data implemenations in one of its parents. 

Закладка Classy Class-based views для просмотра того, что находится в Django CBVs.

Это классическая проблема ООП. У вас есть два наследуемых класса с одним и тем же методом get_context_data(). Целевой класс всегда получает код метода из первого наследуемого класса. В этом случае ListFormView.get_context_data() имеет тот же код, что и AccessCheck.get_context_data(), а класс ListFormView не знает ничего о коде в методе AccessCheck.get_context_data() (где определен self.object_list = ...).

Вот пример:

class First:
    def f(self):
        print('Code from First')

class Second:
    def f(self):
        print('Code from Second')

class A(First, Second):
    pass


A().f() >>> "Code from First"

Возможные решения - переместить правильный класс в начало списка наследования:

#         ╔═══════╗  swithch them
class A(Second, First):
    pass

A().f() >>> "Code from Second"

Или вы можете определить свой собственный метод f в классе A и использовать super с аргументом, чтобы определить, где вы хотите начать обращение к методу. Чтобы определить, что записать в качестве первого аргумента super, выполните команду A.__mro__ и выберите класс перед target в этом списке:

class A(First, Second):    
    def f(self):
        super(First, self).f()

A.__mro__ >>> (<class '__main__.A'>, <class '__main__.First'>, <class '__main__.Second'>, <class 'object'>)
A().f() >>> "Code from Second"

Я рекомендую вам прочитать об ООП в python и множественном наследовании.

* Ваше возможное решение:

# make from this line
class ListFormView(AccessCheck, FormView, ListView)
# this one
class ListFormView(ListView, AccessCheck, FormView)
Вернуться на верх