wagtail-longclaw/docs/walkthrough/products.rst

167 wiersze
6.5 KiB
ReStructuredText

.. _tutorial_products:
Modelling Your Catalogue
========================
Longclaw makes as few assumptions as possible when it comes to modelling your products, since the
requirements of different shops can be wide and varied.
It is required that you create a ``ProductVariant`` model (it can be called anything) and implement
a small number of fields Longclaw expects.
The easiest way to do this is by inheriting from ``longclaw.products.ProductVariantBase``.
Longclaws' project template will have setup a ``products`` app for you, with a ``ProductVariant`` model.
You will also notice that the settings file has ``PRODUCT_VARIANT_MODEL`` set to the ``ProductVariant`` model.
The project template has also created a ``ProductIndex`` and ``Product`` model.
``Product`` is a regular Wagtail ``Page`` which ``ProductVariant`` is an line model of.
.. note::
This is just one way of modelling yor catalogue but you are not bound to it. ``ProductVariant`` is the only model
required by Longclaw and precisely what this represents is up to your (e.g. it could be the product itself, or, as the name
suggests, a variant of a product). You could create multiple 'index' pages, perhaps representing different lines
aswell as multiple 'product' type pages, or do away with ``Product`` completely.
Creating the Product Index
--------------------------
Wagtails' ``Page`` models are organized in a tree structure. All our ``Product`` pages will therefore
need a parent. This is provided by the ``ProductIndex`` model.
.. note::
Read more about Wagtail pages in the `Wagtail docs <http://docs.wagtail.io/en/v1.9/topics/pages.html>`_
To add a product index page:
- Navigate to the admin and log in
- Select the homepage from the explorer menu
- Select ``add child page``
- Select ``Product index`` and enter the title (e.g. `Products`)
.. figure:: ../_static/images/product_index.png
We can now add ``Product`` models as children of ``ProductIndex``. Only pages of type ``Product`` can be created under ``ProductIndex``.
Adding a Product
----------------
Under the explorer homepage, we should now see our newly created ``ProductIndex``. We can select ``Add child page`` to add our first
``Product``. The ``Product`` model is fairly minimal. It has:
- A title
- A description
- One or more ``ProductVariant``s
- Optionally some images and tags
.. figure:: ../_static/images/product.png
Customising
------------
As mentioned above, we can customise the ``ProductIndex`` and ``Product`` model completely - they
are not strict requirements for longclaw to operate. We reccomend using something similar to
the project layout so that ``Product``'s will appear in the Wagtail admin page explorer.
``ProductVariant`` can be customised, as long as we inherit from ``ProductVariantBase`` in order to ensure
the fields longclaw expects are present.
``ProductVariantBase`` provides the ``price``, ``ref`` and ``slug`` fields.
The ``ref`` field is intended to be used as a short description or sub-title to help distinguish a particular variant.
The ``slug`` field is autogenerated from the ``ref`` and the parent ``Product`` title.
As we are creating a music shop, we are going to add a ``music_format`` field to the model. We will also
remove the ``description`` field as we dont have any real need for it at the moment:
.. code-block:: python
class ProductVariant(ProductVariantBase):
_MUSIC_FORMAT_CHOICES = (
(1, 'CD'),
(2, 'Vinyl'),
)
music_format = models.IntegerField(max_length=3, choices=_MUSIC_FORMAT_CHOICES)
After making and running migrations, we can now select the format for each variant:
.. figure:: ../_static/images/product_variant.png
The actual model used for the product variant can be changed by changing the ``PRODUCT_VARIANT_MODEL`` setting in your ``settings.py``
Creating the Front End
=======================
Since ``ProductIndex`` and ``Product`` are Wagtail pages, we write templates for them just like any other page.
The Wagtail documentation already comprehensively covers `writing templates <http://docs.wagtail.io/en/v1.9/topics/writing_templates.html>`_.
Our template project already has some basic templates for ``ProductIndex`` and ``Product``:
- ``my_shop/my_shop/templates/products/product_index.html``
- ``my_shop/my_shop/templates/products/product.html``
They contain just enough information to demonstrate how to traverse the products and their fields.
For a more complete template, take a look at the `demo project <https://github.com/JamesRamm/longclaw_demo>`_.
Adding Products to the Basket
-----------------------------
Longclaw offers a helpful template tag to create an ``Add To Basket`` button for your products.
In your template, load the basket tags::
.. code-block:: django
{% load basket_tags %}
You can now use the tag to render a button for each product variant:
.. code-block:: django
{% add_to_basket_btn variant.id btn_text="Add To Basket" btn_class="btn btn-default" %}
If you wish to create a button manually, you can handle the click event by making an AJAX call to the longclaw API.
Situations where you would prefer this over the tempaltetag might be to support non-button elements, such as
dropdown buttons, or for React-based frontends.
Here is an example with a single button whose 'variant id' will change depending on the selection in a dropdown box.
We can acheive the drop down like this:
.. code-block:: django
<dl>
<dt>Format</dt>
<dd>
<div class="col-md-6">
<select id="variant-select">
{% for variant in page.variants.all %}
<option value="{{variant.id}}">{{variant.music_format}}</option>
{% endfor %}
</select>
</div>
</dd>
</dl>
Add a button:
.. code-block:: django
<button id="add-button">Add To Basket</button>
We can then write a jquery function to handle the click event:
.. code-block:: javascript
$('#add-button').click(function () {
// Selected variant
var variant_id = $('#variant-select option:selected').val();
// Add to the basket
$.post("api/add_to_basket/", { variant_id: variant_id });
});
This is a basic example of integrating with the basket. You will likely need to incorporate more
complex designs such as displaying a count of items in the basket, allowing the user to increase/decrease
quantity and so on. The :ref:`basket API <basket>` allows all such interactions and all front end design decisions such as these are left up to the developer.
It is worthwhile looking at the longclaw demo source code to see how e.g. a basket & item count in the page header is implemented.