Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Héritage de vues avec surcharge de la méthode get_context(self, **kwargs)

+3 votes

Je voudrais ajouter un context supplémentaire à toutes mes vues en héritant de la même vue qui surcharge :

 def get_context_data(self, **kwargs)

J'ai ce code :

class AbstractWithUserView(TemplateView):
def get_context_data(self, **kwargs):
    context = super(AbstractWithUserView, self).get_context_data(**kwargs)
    context['number_of_player'] = self.request.user.team.get_number_of_player()
    context['number_of_coach'] = self.request.user.team.get_number_of_coach()
    context['head_coach'] = self.request.user.team.get_head_coach()
    context['team'] = self.request.user.team
    return context

class Meta:
    abstract = True

Avec un exemple de vue l'utilisant :

class ListPlayerAndCoach(AbstractWithUserView, ListView):
template_name = "staffManagement/playerAndCoach_list.html"

def get_context_data(self, **kwargs):
    context = super(ListPlayerAndCoach, self).get_context_data(**kwargs)
    context['coach_list'] = Coach.objects.filter(member__team =
            self.request.user.team)
    return context

def get_queryset(self):
    return Player.objects.filter(member__team =
            self.request.user.team)

Malheureusement j'ai cette erreur :

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 147, in get_response
 response = wrapped_callback(request, *callback_args, **callback_kwargs)
 File "/usr/local/lib/python2.7/dist-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
 File "/usr/local/lib/python2.7/dist-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/generic/base.py", line 157, in get
context = self.get_context_data(**kwargs)
File "/home/quentin/Documents/salamander/staffManagement/views.py", line 29, in      
get_context_data
context = super(ListPlayerAndCoach, self).get_context_data(**kwargs)
 File "/home/quentin/Documents/salamander/staffManagement/views.py", line 12, in  get_context_data
context = super(AbstractWithUserView, self).get_context_data(**kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/generic/list.py", line 130, in get_context_data
queryset = kwargs.pop('object_list', self.object_list)
AttributeError: 'ListPlayerAndCoach' object has no attribute 'object_list'

Je ne sais pas si je procède de la bonne manière et si il est possible de faire en sorte d’exécuter le code de la classe mère et ensuite d'ajouter d'autre donnée au context.

demandé 10-Fev-2016 par Echel8n (246 points)

Tu nous montre bien tout le code là ? Y a pas une méthode en plus dans une de tes classes ?

Oui, je viens de poster mon code en commentaire du sujet avec ce que je teste et l'erreur claire ainsi que ma possible interprétation.

3 Réponses

+2 votes
 
Meilleure réponse

Remplace:

class AbstractWithUserView(TemplateView)

Par:

class AbstractWithUserView(object)

Et si tu peux, renomme la en WithUserMixin.

Le problème vient du fait que tu hérite de TemplateView, qui définit une méthode get(). Celle-ci est donc appelée en lieu et place de la méthode get() de la ListView. Or, c'est dans cette méthode que object_list est initialisé.

Pour ta classe, tu n'as pas besoin d'hériter d'une vue quelconque. De toute façon, ListView hérite déjà de TemplateView.

Enfin, tu peux virer le abstract = True, ça n'est utile que sur les modèles.

répondu 17-Fev-2016 par Sam (4,984 points)
sélectionné 20-Fev-2016 par Echel8n

J'ai donc remplacé mais j'ai plusieurs soucis qui se posent avec ce code :

class WithUserMixin(object):

def get_context_data(self, **kwargs):
    context = super(WithUserMixin, self).get_context_data(**kwargs)
    context['number_of_player'] = self.request.user.member.team.get_number_of_player()
    try:
        context['head_coach'] = self.request.user.member.team.get_head_coach()
    except:
        context['head_coach'] = None
    context['number_of_coach'] = self.request.user.member.team.get_number_of_coach()
    context['team'] = self.request.user.member.team
    return context

class ListPlayerAndCoach(ListView, WithUserMixin):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = WithUserMixin.get_context_data(self, **kwargs)
        try:
            context = self.get_my_context_data(context)
            context['coach_list'] = Coach.objects.filter(member__team =
                self.request.user.member.team)
        except:
            pass

        return context

    def get_queryset(self):
        return Player.objects.filter(member__team =
                self.request.user.member.team)

J'ai l'erreur :

'super' object has no attribute 'get_context_data'

Je pense comprendre pourquoi puisque j'hérite de object qui lui n'a pas la bonne structure.

Si j'enlevère cette ligne :

context = super(WithUserMixin, self).get_context_data(**kwargs)

j'ai un problème car la variable context n'est pas définie :

global name 'context' is not defined

Je ne sais pas si j'exprime bien mon problème mais j’aimerais que lorsqu'on appelle une vue, ce context soit récupéré automatiquement en fonction de la requête et qu'il soit disponible après.

La solution d'héritage me paraissait la plus simple car j'appelle la méthode getcontextdata lors des appels super(). Je voulais donc appeler la méthode de la classe parente dans la classe fille et ensuite rajouter les éléments au contexte avec la classe fille.

Dans la définition de la classe ListPlayerAndCoach on met le mixin avant la View
Dans get_context_data de ListPlayerAndCoach on fait pas d'appel a mixin, c'est justement fait via l'héritage . donc on peuple le context coach et c'est tout

class ListPlayerAndCoach(WithUserMixin, ListView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = super(ListPlayerAndCoach, self).get_context_data(**kwargs)
        context['coach_list'] = Coach.objects.filter(member__team = self.request.user.member.team)

        return context

Remet super(), maintenant qu'on a un mixing propre, il va bien marcher. WithUserMixin.getcontextdata(self, kwargs) => super(ListPlayerAndCoach, self).getcontextdata(kwargs)

J'avais fait ça en premier lieu mais le problème c'est que la méthode de mon mixin n'est pas appelé en fait.

class WithUserMixin(object):

def get_context_data(self, **kwargs):
    context = super(WithUserMixin, self).get_context_data(**kwargs)
    print '\nFoo\n'
    context['number_of_player'] = self.request.user.member.team.get_number_of_player()
    try:
        context['head_coach'] = self.request.user.member.team.get_head_coach()
    except:
        context['head_coach'] = None
    context['number_of_coach'] = self.request.user.member.team.get_number_of_coach()
    context['team'] = self.request.user.member.team
    return context

class Meta:
    abstract = True


class ListPlayerAndCoach(WithUserMixin, ListView):
template_name = "staffManagement/playerAndCoach_list.html"

def get_context_data(self, **kwargs):
    context = super(WithUserMixin, self).get_context_data(**kwargs)
    try:
        context['coach_list'] = Coach.objects.filter(member__team =
            self.request.user.member.team)
    except:
        pass

    return context

def get_queryset(self):
    return Player.objects.filter(member__team =
            self.request.user.member.team)

comme a dit SAM ,
il ne faut pas faire

class ListPlayerAndCoach(WithUserMixin, ListView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = super(WithUserMixin, self).get_context_data(**kwargs)

mais

class ListPlayerAndCoach(WithUserMixin, ListView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = super(ListPlayerAndCoach, self).get_context_data(**kwargs)

et la ca passera

Effectivement, merci.

+1 vote

Je crois que quand tu utilises de l'héritage multiple, le mieux est de ne pas utiliser super mais d'appeler directement la méthode parent.

Dans ton cas ça donnerait :

class ListPlayerAndCoach(AbstractWithUserView, ListView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = AbstractWithUserView.get_context_data(self, **kwargs)
        context['coach_list'] = Coach.objects.filter(member__team =
            self.request.user.team)
        return context

def get_queryset(self):
    return Player.objects.filter(member__team =
        self.request.user.team)

Note l'usage de :

context = AbstractWithUserView.get_context_data(self, **kwargs)

À la place de :

context = super(ListPlayerAndCoach, self).get_context_data(**kwargs)
répondu 10-Fev-2016 par ziirish (158 points)

Oui c'est vrai que ca parait logique d'utiliser la méthode parent, néanmoins cela ne fonctionne pas avec votre bout de code.

J'ai cette erreur :

global name 'context' is not defined

dans ce bout de code :

from django.core.urlresolvers import reverse_lazy

"""

        Abstract view to add user context data

"""

class AbstractWithUserView(TemplateView):

    def get_context_data(self, **kwargs):

        context['number_of_player'] = self.request.user.member.team.get_number_of_player()

 ...

        context['number_of_coach'] = self.request.user.member.team.get_number_of_coach()

        context['head_coach'] = self.request.user.member.team.get_head_coach()

        context['team'] = self.request.user.member.team

        return context

Je ne peux récupérer le champs self.resquest.user dans la classe mère

Pourquoi avoir supprimé cette ligne ?

context = super(AbstractWithUserView, self).get_context_data(**kwargs)

L'erreur est assez explicite, tu utilises une variable non déclarée.
J'ai dit qu'il fallait éviter super en cas d'héritage multiple. Dans ta classe AbstractWithUserView ça n'est pas le cas puisque tu n'hérites que de TemplateView.

Donc ce code devrait fonctionner :

class AbstractWithUserView(TemplateView):
    def get_context_data(self, **kwargs):
        context = super(AbstractWithUserView, self).get_context_data(**kwargs)
        context['number_of_player'] = self.request.user.team.get_number_of_player()
        context['number_of_coach'] = self.request.user.team.get_number_of_coach()
        context['head_coach'] = self.request.user.team.get_head_coach()
        context['team'] = self.request.user.team
        return context

class Meta:
    abstract = True

Puis tu l'appeles comme ça :

class ListPlayerAndCoach(AbstractWithUserView, ListView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = AbstractWithUserView.get_context_data(self, **kwargs)
        context['coach_list'] = Coach.objects.filter(member__team =
            self.request.user.team)
        return context

    def get_queryset(self):
        return Player.objects.filter(member__team = self.request.user.team)

Oui effectivement c'est un oublis bête de ma part.

Néanmoins j'ai cette erreur qui me laisse supposé que le fait de faire charger la méthode depuis la classe mère héritant de TemplateView ne fourni pas tous les éléments nécessaire à la classe fille :

'ListPlayerAndCoach' object has no attribute 'object_list'

J'ai essayé pas mal de truc mais sans succès. Auriez-vous une idée ?

+1 vote

Voici le code que j'utilise actuellement pour contourner ce problème.

Code sur Pastebin

Voici le code que je teste :

class AbstractWithUserView(TemplateView):
    def get_context_data(self, **kwargs):
        context = super(AbstractWithUserView, self).get_context_data(**kwargs)

        context['number_of_player'] = self.request.user.member.team.get_number_of_player()
        try:
            context['head_coach'] = self.request.user.member.team.get_head_coach()
        except:
            context['head_coach'] = None
        context['number_of_coach'] = self.request.user.member.team.get_number_of_coach()
        context['team'] = self.request.user.member.team
        return context

    class Meta:
        abstract = True


class ListPlayerAndCoach(ListView, AbstractWithUserView):
    template_name = "staffManagement/playerAndCoach_list.html"

    def get_context_data(self, **kwargs):
        context = AbstractWithUserView.get_context_data(self, **kwargs)
        try:
            context = self.get_my_context_data(context)
            context['coach_list'] = Coach.objects.filter(member__team =
                self.request.user.member.team)
        except:
            pass

        return context

    def get_queryset(self):
        return Player.objects.filter(member__team =
                self.request.user.member.team)

Et j'obtiens cette erreur :

'ListPlayerAndCoach' object has no attribute 'object_list'

D'après ce que je comprend c'est qu'en héritant ListPlayerAndCoach de AbstractWithUserView qui hérite de TemplateView, ma classe ListPlayerAndCoach n'hérite pas des variables nécessaires ('objectlist') lorsque je fais ListPlayerAndCoach.asview() dans mon url.
Néanmoins je ne sais pas si mon interprétation est bonne et si c'est le cas je ne sais pas comment faire.

répondu 17-Fev-2016 par Echel8n (246 points)
...