1👍
It is added by the metaclass, but in a bit of a cryptical way. Indeed, in the _preprare
class of the ModelBase
which is not the superclass of a Model
, but its typeclass, contributes this to the class [src]:
def _prepare(cls): # … if not opts.managers: # … cls.add_to_class("objects", manager) # …
The .add_to_class
method will call the .add_to_class
on the manager, that will then set itself as attribute on the class object.
The claim that every model has however an .objects
is not true. This is only the case if you do not specify a manager yourself. Indeed, if you define a model:
class MyModel(models.Model):
mymanager = models.Manager()
Then MyManager
will not contain an .objects
.
As for the .all()
method itself, it works with the _get_queryset_methods
. These return a dictionary with the name of the methods and its method. This will thus return a dictionary that maps 'all'
to a method that returns self.get_queryset().all()
, since get_queryset
will return a QuerySet
, it will thus call .all()
on that queryset [src]:
@classmethod def _get_queryset_methods(cls, queryset_class): def create_method(name, method): @wraps(method) def manager_method(self, *args, **kwargs): return getattr(self.get_queryset(), name)(*args, **kwargs) return manager_method new_methods = {} for name, method in inspect.getmembers( queryset_class, predicate=inspect.isfunction ): # Only copy missing methods. if hasattr(cls, name): continue # Only copy public methods or methods with the attribute # queryset_only=False. queryset_only = getattr(method, "queryset_only", None) if queryset_only or (queryset_only is None and name.startswith("_")): continue # Copy the method onto the manager. new_methods[name] = create_method(name, method) return new_methods
Most IDE’s, code analysis tools, etc. will indeed not be capable to derive that a model has an .objects
attribute, because it originates out of some sophisticated code in the typeclass.
PyCharm professional however has a Django plugin that can "understand" Django better, because the developers have hardcoded such logic. It thus contains some logic that does not analyze the typeclass code, but simply knows, because the developers of the module say that, added the manager.
Python is very flexible, dynamically-typed language, which often is a good idea. But code analysis sometimes can not follow the complexity of metaclasses, etc. and thus eventually fail to see how items are added to a class, which is a downside, compared to statically typed languages, for example.