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)