Add custom manager so the `objects` property can be accessed by instances

A normal manager prevents instances from accessing the `objects` property.
This implementation uses the `objects` as the accessor to the set's
underlying objects queryset. This proxies to the `ObjectSet._objects`
property.
Change implementation of cached_property to be class-based

This prevents binding additional properties to the instance and instead
replaces the value in the internal dict with the result of the first call.
Add more documentation to ObjectSet methods and properties