As a personal anecdote,I have not at all found this for drf. I personally dread every time something goes wrong in our api code, it's a sea of overcomplicated inheritance trees (some of this is our fault, but it's at drfs direction imo) and factors that eventually just end up with me never being able to find where anything actually happens, other than via a mountain of print statements.
Django by contrast, I agree, it's perfectly clear. (Though some of the meta magic does get spooky, but that's the nature of meta magic, and I generally find the tradeoffs are worth it)
You basically have either a property or a function with the name get_property for a certain number of things (queryset, serialiser, pagination class, etc.) in any case. I tend to recommend in our projects style guides that once you want to override the behaviour of a mixin, you don’t inherit from the mixin anymore.
The two biggest issues I came across with teams in DRF were people coupling the serialised directly to a single database model (i.e. using ModelSerializer everywhere, even when that didn’t make sense), and trying to put too much stuff into a single class based view or viewset.
I find DRF has a lot of places where someone can alter the behavior of handling the request, which can make it really hard to track down where some field or behavior is coming from. You can define methods on the view, serializer, model, or filter (or some superclass of these) to totally change how some response is formed. It is very flexible, and can save a lot of typing if you have all the conventions in your head (and everybody working on a project strictly follows the same conventions). But I find plain Django or something like Flask much easier to grok.
Django by contrast, I agree, it's perfectly clear. (Though some of the meta magic does get spooky, but that's the nature of meta magic, and I generally find the tradeoffs are worth it)