algo_rism
@algo_rism

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

drfのMixinで継承関係もインスタンスメソッドもないのに、メソッドが使えるのはなぜか

解決したいこと

drfのviewを実装するときにmixinsの中のlistmodelmixinを使うのですが、下記のコードの通り
listmodelmixinは、何かの具象クラスでもなければ、内部でインスタンスメソッドが定義されているわけではありません。なのにself.filter_querysetのようなメソッドが使えるのはなぜですか?

該当するソースコード

class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
0

1Answer

なのにself.filter_querysetのようなメソッドが使えるのはなぜですか?

通常、ユーザが、ListModelMixin クラスを含めた多重継承を行う際、多重継承している他のクラスがそれらメソッドを持っているからです。

ユーザが独自の View を実装する際に、ListModelMixin は、たいてい generics.GenericAPIView クラスか、viewsets.GenericViewSet と一緒に使われます(多重継承)。

たとえば下記のような感じです。
引用:https://qiita.com/popo62520908/items/a7d702d673b212c0cfa4

from rest_framework import generics
from rest_framework import mixins
from ebooks.models import Ebook
from .serializers import EbookSerializer

class EbookListCreateAPIView(mixins.ListModelMixin, 
                             mixins.CreateModelMixin, 
                             generics.GenericAPIView):
    queryset = Ebook.objects.all()
    serializer_class = EbookSerializer
    #querysetとserializer_classを定義

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs) #list

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs) #create

filter_queryset メソッドや paginate_queryset メソッドは、この generics.GenericAPIView クラスで実装されています。

※ viewsets.GenericViewSet は、上記 generics.GenericAPIViewクラスを継承しています。

仮に上記以外のクラスを継承しており、そのクラスがこれらのメソッドを持っていない場合は、ユーザが各メソッドを独自に実装しなければなりません。


Javaのような言語に慣れている方からすれば不思議かもしれませんが、pythonは動的言語なので、コードを定義した時点で、メソッドを持っているクラスが明示的に指定されている必要はありません。
実行時に、その時点で多重継承されている他のクラスのメソッドを探しにいきます。その際、兄弟クラスまで見に行ってくれます。
なので、上のようなことが可能となっています。

1Like

Your answer might help someone💌