kopia lustrzana https://github.com/longclawshop/longclaw
167 wiersze
6.5 KiB
ReStructuredText
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.
|