Top Banner
Writing a Django ecommerce framework OSCON 2012 Friday, 20 July 12
60

Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Apr 03, 2018

Download

Documents

leliem
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Writing  a  Django  e-­‐commerce  framework

OSCON  2012

Friday, 20 July 12

Page 2: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Me•David  Winterbottom  /  @codeinthehole

•Tangent  Labs,  London

•Head  of  E-­‐commerce  team

•Python  hacker

•commandlinefu.com,  django-­‐oscar

Friday, 20 July 12

Page 3: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Synopsis•Motivation

•Oscar  -­‐  what  problem  does  it  solve?

•Design  decisions  -­‐  customisation  techniques

•E-­‐commerce  tips/advice

Friday, 20 July 12

Page 4: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Motivation

Friday, 20 July 12

Page 5: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

•5  years  of  e-­‐commerce  projects

•PHP  =>  Python  /  Django

•Lots  of  war  stories

Tangent  Labs

Friday, 20 July 12

Page 6: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Books

Friday, 20 July 12

Page 7: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Bookshop  domain•Millions  of  products

•ISBNs,  BIC/BISAC  categories,  authors,  publishers

•Automated  feed-­‐driven  processing

•Catalogue

•Stock

•Rich  data

Friday, 20 July 12

Page 8: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

Page 9: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Variations•New  fulfilment  partners

•Stock/availability  logic

•Multiple  payment  partners

•Split-­‐payment  sources

•Multibuy  offers,  vouchers

•eBooks!

Friday, 20 July 12

Page 10: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

PHP  framework•Home-­‐rolled  web  framework

•Customisation  via  include  path  overrides

•Lots  of  duplication

•Hard  to  upgrade

Friday, 20 July 12

Page 11: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Nailvarnish

Friday, 20 July 12

Page 12: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

T-­‐shirts

Friday, 20 July 12

Page 13: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Digital  music

Friday, 20 July 12

Page 14: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Bar  equipment

Friday, 20 July 12

Page 15: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

•New  fulfilment  processes:  

•webservices  /  warehouses

•Per-­‐customer  prices

Friday, 20 July 12

Page 16: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

B2B•Sales  reps,  customer  hierarchies

•Tax  rules

•Managed  budgets

•Integration  with  “enterprise”  partners

Friday, 20 July 12

Page 17: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

•Original  assumptions  all  broken

•Domains  vary  wildly

•Lots  of  work-­‐arounds

Friday, 20 July 12

Page 18: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Oscar

Friday, 20 July 12

Page 19: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Requirements•Lean  -­‐  as  few  assumptions  as  possible

•Models  domain  

•without  duplication

•without  too  much  meta-­‐data

Friday, 20 July 12

Page 20: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Friday, 20 July 12

Page 21: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Domain  modelling•Implementation  deeply  connected  to  core  business  concepts

•“...where  powerful  new  features  unfold  as  corollaries  to  older  features.”

Friday, 20 July 12

Page 22: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Friday, 20 July 12

Page 23: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Lots  of  others•Satchmo  

•Lightning-­‐Fast-­‐Shop

•Satchless

•Django-­‐shop

•Plata,  Mamona,  Cartridge,  ...

•http://djangopackages.com/grids/g/ecommerce/

Friday, 20 July 12

Page 24: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Design  decisions

Friday, 20 July 12

Page 25: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Python

•Decimal  support

•**kwargs

•Mixins

Friday, 20 July 12

Page 26: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Friday, 20 July 12

Page 27: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Web  framework

•Well-­‐thought  out  structure

•Templating,  HTTP,  security,  caching,  ...

•Class-­‐based  views

Friday, 20 July 12

Page 28: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Models

•Models  drive  the  design

•Capture  domain  logic

•Foundation  for  rest  of  application

Friday, 20 July 12

Page 29: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Eco-­‐system•Haystack  (search)

•South  (database  migrations)

•Celery  (job  queue)

•Internal  libraries

Friday, 20 July 12

Page 30: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Customisation

Friday, 20 July 12

Page 31: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

DEBUG = True

settings.py

Friday, 20 July 12

Page 32: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

AUTH_PROFILE_MODULE = ‘customer.Profile’

settings.py

Friday, 20 July 12

Page 33: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Different  approach

•Key  idea:

•Having  the  same  name/identifier  as  your  parent  

•Subclass  and  override

Friday, 20 July 12

Page 34: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

 Templates

Friday, 20 July 12

Page 35: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Friday, 20 July 12

Page 36: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader',)

TEMPLATE_DIRS = ( '/var/www/project/templates/',)

Replace

Friday, 20 July 12

Page 37: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader',)

TEMPLATE_DIRS = ( '/var/www/project/templates/' '/path/to/oscar/',)

Override

parent  of  Oscar’s  template  directory

Friday, 20 July 12

Page 38: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

# base.html

{% extends 'templates/base.html' %}

{% block scripts %}<script src="new.js" type="text/javascript"></script>{% endblock %}

Override

Friday, 20 July 12

Page 39: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

# base.html

{% extends 'templates/base.html' %}

{% block scripts %}<script src="new.js" type="text/javascript"></script>{{ block.super }}{% endblock %}

Extend

Friday, 20 July 12

Page 40: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

Page 41: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Apps

Friday, 20 July 12

Page 42: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

from django.db.loading import get_model

Line = get_model('basket', 'Line')

Dynamic  loading  1

INSTALLED_APPS = ( 'oscar.apps.basket')

Friday, 20 July 12

Page 43: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

Page 44: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

INSTALLED_APPS = ( 'oscar', 'oscar.apps.catalogue', 'oscar.apps.basket', 'oscar.apps.checkout', 'oscar.apps.order', ...)

Friday, 20 July 12

Page 45: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

INSTALLED_APPS = ( 'oscar', 'oscar.apps.catalogue', 'myproject.basket', 'oscar.apps.checkout', 'oscar.apps.order', ...)

Same  app  label  as  parent  app

Friday, 20 July 12

Page 46: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

# myproject/basket/models.py

from django.db import modelsfrom 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

Page 47: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

INSTALLED_APPS = ( 'oscar', 'oscar.apps.catalogue', 'oscar.apps.basket', 'oscar.apps.checkout', 'oscar.apps.order', ...)

templatetagsmanagement  commands

Friday, 20 July 12

Page 48: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Recap

•App  label    is  the  ID

•Models  can  overridden  and  extended

Friday, 20 July 12

Page 49: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

from oscar.core.loading import get_class

OrderCreator = get_class('order.utils', 'OrderCreator')

Dynamic  loading  2

Friday, 20 July 12

Page 50: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

# 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

Page 51: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Recap

•(App  module,  class  name)    is  the  ID

•Any  class  can  be  overridden  or  extended

Friday, 20 July 12

Page 52: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Tips  and  advice

Friday, 20 July 12

Page 53: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Log  everything...except  sensitive  customer  details.

Friday, 20 July 12

Page 54: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Audit  models

Friday, 20 July 12

Page 55: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

Page 56: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

•High  and  low  thresholds

•It’s  always  your  fault  when  things  go  wrong

Monitor  everything

Friday, 20 July 12

Page 57: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

Service  layers•Avoid  views  talking  to  your  models  directly

•See  ‘Facade’  design  pattern

•Anti-­‐corruption  layers

Friday, 20 July 12

Page 58: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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

Page 59: Writing’a’Django’ ecommerce’ - O'Reilly Mediaassets.en.oreilly.com/1/event/80/Writing a Django e-Commerce... · from django.db import models class NielsenDataFile(models.Model):

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