123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- =======================
- How to customise models
- =======================
-
- This How-to describes how to replace Oscar models with your own. This allows you
- to add fields and custom methods. It builds upon the steps described in
- :doc:`/topics/customisation`. Please read it first and ensure that you've:
-
- * Created a Python module with the the same app label
- * Added it as Django app to ``INSTALLED_APPS``
- * Added a :file:`models.py` and :file:`admin.py`
-
- Example
- -------
-
- Suppose you want to add a ``video_url`` field to the core product model. This means
- that you want your application to use a subclass of
- :class:`oscar.apps.catalogue.abstract_models.AbstractProduct` which has an additional field.
-
- The first step is to create a local version of the "catalogue" app. At a minimum, this
- involves creating :file:`catalogue/models.py` within your project and changing ``INSTALLED_APPS``
- to point to your local version rather than Oscar's.
-
- Next, you can modify the ``Product`` model through subclassing::
-
- # yourproject/catalogue/models.py
-
- from django.db import models
-
- from oscar.apps.catalogue.abstract_models import AbstractProduct
-
- class Product(AbstractProduct):
- video_url = models.URLField()
-
- from oscar.apps.catalogue.models import *
-
- Make sure to import the remaining Oscar models at the bottom of your file.
-
- .. tip::
-
- Using ``from ... import *`` is strange isn't it? Yes it is, but it needs to
- be done at the bottom of the module due to the way Django registers models.
- The order that model classes are imported makes a difference, with only the
- first one for a given class name being registered.
-
- The last thing you need to do now is make Django update the database schema and
- create a new column in the product table. We recommend using migrations
- for this (internally Oscar already does this) so all you need to do is create a
- new schema migration.
-
- It is possible to simply create a new catalogue migration (using ``./manage.py
- makemigrations catalogue``) but this isn't recommended as any
- dependencies between migrations will need to be applied manually (by adding a
- ``dependencies`` attribute to the migration class).
-
- The recommended way to handle migrations is to copy the ``migrations`` directory
- from ``oscar/apps/catalogue`` into your new ``catalogue`` app. Then you can
- create a new (additional) migration using the ``makemigrations``
- management command::
-
- ./manage.py makemigrations catalogue
-
- which will pick up any customisations to the product model.
-
- To apply the migration you just created, all you have to do is run
- ``./manage.py migrate catalogue`` and the new column is added to the product
- table in the database.
-
- Customising Products
- --------------------
-
- You should inherit from ``AbstractProduct`` as above to alter behaviour for all
- your products. Further subclassing is not recommended, because using methods
- and attributes of concrete subclasses of ``Product`` are not available unless
- you explicitly cast them onto that class. To model different classes of
- products, use ``ProductClass`` and ``ProductAttribute`` instead.
-
- Model customisations are not picked up
- --------------------------------------
-
- It's a common problem that you're trying to customise one of Oscar's models,
- but your new fields don't seem to get picked up. That is usually caused by
- Oscar's models being imported before your customised ones. Django's model
- registration disregards all further model declarations.
-
- In your overriding :file:`models.py`, ensure that you import Oscar's models *after*
- your custom ones have been defined. If that doesn't help, you have an import
- from ``oscar.apps.*.models`` somewhere that is being executed before your models
- are parsed. One trick for finding that import: put ``assert False`` in the relevant
- Oscar's :file:`models.py`, and the stack trace will show you the importing module.
-
- If other modules need to import your models, then import from your local module,
- not from Oscar directly.
-
- Customising dashboard forms
- ---------------------------
-
- For example, we have customised Product model and have added several fields.
- And we want to show it in the form for editing. You can customise dashboard
- forms by creating your own form that subclasses Oscar's dashboard form for
- any model. For example, you can customise the ``Product`` form in
- :file:`apps/dashboard/catalogue/forms.py` as follows::
-
- from oscar.apps.dashboard.catalogue import forms as base_forms
-
- class ProductForm(base_forms.ProductForm):
-
- class Meta(base_forms.ProductForm.Meta):
-
- fields = (
- 'title', 'upc', 'on_sale',
- 'short_description', 'description',
- 'out_of_stock', 'bestseller',
- 'is_new', 'is_discountable', 'structure',
- 'markdown', 'markdown_reason')
-
-
- Finally, make sure that you have overridden the dashboard app in your settings:
- replace ``'oscar.apps.dashboard.catalogue'`` with ``'apps.dashboard.catalogue'``
- in the ``INSTALLED_APPS`` setting.
|