123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- ===============================
- Dynamic class loading explained
- ===============================
-
- Dynamic class loading is the foundation for making Oscar extensively
- customisable. It is hence worth understanding how it works, because most
- customisation depends on it.
-
- It is achieved by :meth:`oscar.core.loading.get_classes` and its
- single-class cousin :meth:`~oscar.core.loading.get_class`. Wherever feasible,
- Oscar uses ``get_classes`` instead of a regular import statement:
-
- .. code-block:: python
-
- from oscar.apps.shipping.repository import Repository
-
- is replaced by:
-
- .. code-block:: python
-
- from oscar.core.loading import get_class
-
- Repository = get_class('shipping.repository', 'Repository')
-
- .. note:: This is done for almost all classes: views, models, etc. Every class
- imported by ``get_class`` can be overridden.
-
- Why?
- ----
-
- This structure enables a project to create a local ``shipping.repository``
- module, and optionally subclass the class from
- ``oscar.apps.shipping.repository``. When Oscar tries to load the
- ``Repository`` class, it will load the one from your local project.
-
- This way, most classes can be overridden with minimal duplication, as only
- the to-be-changed classes have to be altered. They can optionally inherit from
- Oscar's implementation, which often amounts to little more than a few lines of
- custom code for changes to core behaviour.
-
- Seen on a bigger scale, this structures enables Oscar to ship with classes with
- minimal assumptions about the domain, and make it easy to modify behaviour as
- needed.
-
- How it works
- ------------
-
- The ``get_class`` function looks through your ``INSTALLED_APPS`` for a matching
- app and will attempt to load the custom class from the specified module. If the
- app isn't overridden or the custom module doesn't define the class, it will
- fall back to the default Oscar class.
-
- In practice
- -----------
-
- For ``get_class`` to pick up the customised class, the Oscar apps need to be
- forked. The process is detailed and illustrated with examples in
- :doc:`/topics/customisation`. It is usually enough to call ``oscar_fork_app``
- and replace the app in ``INSTALLED_APPS``.
-
- Using ``get_class`` in your own code
- ------------------------------------
-
- Generally, there is no need for ``get_class`` in your own code as the location
- of the module for the class is known. Some Oscar developers nonetheless
- use ``get_class`` when importing classes from Oscar. This means that if someday
- the class is overridden, it will not require code changes. Care should be taken
- when doing this, as this is a tricky trade-off between maintainability and
- added complexity.
- Please note that we cannot recommend ever using ``get_model`` in your own code.
- Model initialisation is a tricky process and it's
- easy to run into circular import issues.
-
-
- Overriding dynamic class loading behaviour
- ------------------------------------
-
- In some cases it may be necessary to customise the logic used by Oscar to
- dynamically load classes. You can do this by supplying your own class loader
- function to the ``OSCAR_DYNAMIC_CLASS_LOADER`` setting:
-
- .. code-block:: python
-
- OSCAR_DYNAMIC_CLASS_LOADER = 'myproject.custom_class_loader'
-
- Supply a dotted Python path to a callable that takes
- the same arguments as :meth:`~oscar.core.loading.default_class_loader`.
-
-
- Testing
- -------
-
- You can test whether your overriding worked by trying to get a class from your
- module:
-
- .. code-block:: python
-
- >>> from oscar.core.loading import get_class
- >>> get_class('shipping.repository', 'Repository')
- yourproject.shipping.repository.Repository # it worked!
|