Writing a Django e-commerce framework

Writing a Django e-commerce framework

From OSCON 2012. This presentation discusses the reasons for writing an e-commerce framework and details a number of techniques for customising Django apps.

52d39c7b27386ca98bc016119d95b8b8?s=128

David Winterbottom

July 18, 2012
Tweet

Transcript

  1. 2.

    Me •David  Winterbottom  /  @codeinthehole •Tangent  Labs,  London •Head  of

     E-­‐commerce  team •Python  hacker •commandlinefu.com,  django-­‐oscar Friday, 20 July 12
  2. 3.

    Synopsis •Motivation •Oscar  -­‐  what  problem  does  it  solve? •Design

     decisions  -­‐  customisation  techniques •E-­‐commerce  tips/advice Friday, 20 July 12
  3. 5.

    •5  years  of  e-­‐commerce  projects •PHP  =>  Python  /  Django

    •Lots  of  war  stories Tangent  Labs Friday, 20 July 12
  4. 7.

    Bookshop  domain •Millions  of  products •ISBNs,  BIC/BISAC  categories,  authors,  publishers

    •Automated  feed-­‐driven  processing •Catalogue •Stock •Rich  data Friday, 20 July 12
  5. 8.

    Two  tier  structure •Application  tier  -­‐  serves  HTTP  requests •Processing

     tier: •Download  and  import  feeds •Data  cleaning  and  processing •Periodic  jobs  for  fulfilment Friday, 20 July 12
  6. 10.

    PHP  framework •Home-­‐rolled  web  framework •Customisation  via  include  path  overrides

    •Lots  of  duplication •Hard  to  upgrade Friday, 20 July 12
  7. 15.

    New  requirements •Product  variations  -­‐  colours,  sizes  etc •New  fulfilment

     processes:   •webservices  /  warehouses •Per-­‐customer  prices Friday, 20 July 12
  8. 19.

    Requirements •Lean  -­‐  as  few  assumptions  as  possible •Models  domain

      •without  duplication •without  too  much  meta-­‐data Friday, 20 July 12
  9. 21.

    Domain  modelling •Implementation  deeply   connected  to  core  business  

    concepts •“...where  powerful  new   features  unfold  as  corollaries  to   older  features.” Friday, 20 July 12
  10. 23.

    Lots  of  others •Satchmo   •Lightning-­‐Fast-­‐Shop •Satchless •Django-­‐shop •Plata,  Mamona,

     Cartridge,  ... •http://djangopackages.com/grids/g/ecommerce/ Friday, 20 July 12
  11. 33.

    Different  approach •Key  idea: •Having  the  same  name/identifier  as  your

     parent   •Subclass  and  override Friday, 20 July 12
  12. 38.

    # base.html {% extends 'templates/base.html' %} {% block scripts %}

    <script src="new.js" type="text/javascript"></script> {% endblock %} Override Friday, 20 July 12
  13. 39.

    # base.html {% extends 'templates/base.html' %} {% block scripts %}

    <script src="new.js" type="text/javascript"></script> {{ block.super }} {% endblock %} Extend Friday, 20 July 12
  14. 40.

    Recap •Filename  is  the  ID •Use  include-­‐path  trick  to  “subclass”

     parent   •Use  blocks  to  provide  hook  points •...but,  don’t  go  too  far Friday, 20 July 12
  15. 42.

    from django.db.loading import get_model Line = get_model('basket', 'Line') Dynamic  loading

     1 INSTALLED_APPS = ( 'oscar.apps.basket' ) Friday, 20 July 12
  16. 43.

    from django.db.loading import get_model Line = get_model('basket', 'Line') Dynamic  loading

     1 INSTALLED_APPS = ( 'oscar.apps.basket' ) ‘App  label’ Friday, 20 July 12
  17. 46.

    # myproject/basket/models.py from django.db import models from oscar.apps.basket.abstract_models import \

    AbstractLine class Line(AbstractLine): cost_centre = models.CharField(max_length=64) from oscar.apps.basket.models import * Friday, 20 July 12
  18. 50.

    # order/utils.py from oscar.apps.order.utils import OrderCreator as \ CoreOrderCreator class

    OrderCreator(CoreOrderCreator): def allocate_stock(self, line): # Override/extend method ... Friday, 20 July 12
  19. 51.

    Recap •(App  module,  class  name)    is  the  ID •Any

     class  can  be  overridden  or  extended Friday, 20 July 12
  20. 55.

    from django.db import models class NielsenDataFile(models.Model): filepath = models.CharField(max_length=128) PENDING,

    FAILED, PROCESSED = range(3) status = models.IntegerField(default=PENDING) num_valid_records = models.IntegerField() num_invalid_records = models.IntegerField() date_downloaded = models.DateTimeField(null=True) date_processed = models.DateTimeField(null=True) Friday, 20 July 12
  21. 56.

    •High  and  low  thresholds •It’s  always  your  fault  when  things

     go  wrong Monitor  everything Friday, 20 July 12
  22. 57.

    Service  layers •Avoid  views  talking  to  your  models  directly •See

     ‘Facade’  design  pattern •Anti-­‐corruption  layers Friday, 20 July 12
  23. 58.

    Generic  vs  bespoke •“If  you’re  using  a  framework,  you  aren’t

     doing  good   modelling” •Capture  the  domain  correctly   •It’s  ok  to  throw  away  the  framework Friday, 20 July 12
  24. 59.

    Summary •Django  is  great  for  modelling  complex  domains •Writing  customisable

     django  apps  isn’t  easy •Oscar’s  future:   •NoSQL  -­‐  no  more  EAV Friday, 20 July 12