[Answered ]-Where is `.objects` attribute is added to an instance namespace in django's models.Model class?

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.

Leave a comment