Writing
a
Django
e-‐commerce
framework
OSCON
2012
Friday, 20 July 12
Slide 2
Slide 2 text
Me
•David
Winterbottom
/
@codeinthehole
•Tangent
Labs,
London
•Head
of
E-‐commerce
team
•Python
hacker
•commandlinefu.com,
django-‐oscar
Friday, 20 July 12
Slide 3
Slide 3 text
Synopsis
•Motivation
•Oscar
-‐
what
problem
does
it
solve?
•Design
decisions
-‐
customisation
techniques
•E-‐commerce
tips/advice
Friday, 20 July 12
Slide 4
Slide 4 text
Motivation
Friday, 20 July 12
Slide 5
Slide 5 text
•5
years
of
e-‐commerce
projects
•PHP
=>
Python
/
Django
•Lots
of
war
stories
Tangent
Labs
Friday, 20 July 12
Slide 6
Slide 6 text
Books
Friday, 20 July 12
Slide 7
Slide 7 text
Bookshop
domain
•Millions
of
products
•ISBNs,
BIC/BISAC
categories,
authors,
publishers
•Automated
feed-‐driven
processing
•Catalogue
•Stock
•Rich
data
Friday, 20 July 12
Slide 8
Slide 8 text
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
PHP
framework
•Home-‐rolled
web
framework
•Customisation
via
include
path
overrides
•Lots
of
duplication
•Hard
to
upgrade
Friday, 20 July 12
Slide 11
Slide 11 text
Nailvarnish
Friday, 20 July 12
Slide 12
Slide 12 text
T-‐shirts
Friday, 20 July 12
Slide 13
Slide 13 text
Digital
music
Friday, 20 July 12
Slide 14
Slide 14 text
Bar
equipment
Friday, 20 July 12
Slide 15
Slide 15 text
New
requirements
•Product
variations
-‐
colours,
sizes
etc
•New
fulfilment
processes:
•webservices
/
warehouses
•Per-‐customer
prices
Friday, 20 July 12
Slide 16
Slide 16 text
B2B
•Sales
reps,
customer
hierarchies
•Tax
rules
•Managed
budgets
•Integration
with
“enterprise”
partners
Friday, 20 July 12
Slide 17
Slide 17 text
•Original
assumptions
all
broken
•Domains
vary
wildly
•Lots
of
work-‐arounds
Friday, 20 July 12
Slide 18
Slide 18 text
Oscar
Friday, 20 July 12
Slide 19
Slide 19 text
Requirements
•Lean
-‐
as
few
assumptions
as
possible
•Models
domain
•without
duplication
•without
too
much
meta-‐data
Friday, 20 July 12
Slide 20
Slide 20 text
Friday, 20 July 12
Slide 21
Slide 21 text
Domain
modelling
•Implementation
deeply
connected
to
core
business
concepts
•“...where
powerful
new
features
unfold
as
corollaries
to
older
features.”
Friday, 20 July 12
Slide 22
Slide 22 text
Friday, 20 July 12
Slide 23
Slide 23 text
Lots
of
others
•Satchmo
•Lightning-‐Fast-‐Shop
•Satchless
•Django-‐shop
•Plata,
Mamona,
Cartridge,
...
•http://djangopackages.com/grids/g/ecommerce/
Friday, 20 July 12
Slide 24
Slide 24 text
Design
decisions
Friday, 20 July 12
Slide 25
Slide 25 text
Python
•Decimal
support
•**kwargs
•Mixins
Friday, 20 July 12
Slide 26
Slide 26 text
Friday, 20 July 12
Slide 27
Slide 27 text
Web
framework
•Well-‐thought
out
structure
•Templating,
HTTP,
security,
caching,
...
•Class-‐based
views
Friday, 20 July 12
Slide 28
Slide 28 text
Models
•Models
drive
the
design
•Capture
domain
logic
•Foundation
for
rest
of
application
Friday, 20 July 12
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
Slide 41
Slide 41 text
Apps
Friday, 20 July 12
Slide 42
Slide 42 text
from django.db.loading import get_model
Line = get_model('basket', 'Line')
Dynamic
loading
1
INSTALLED_APPS = (
'oscar.apps.basket'
)
Friday, 20 July 12
Slide 43
Slide 43 text
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
INSTALLED_APPS = (
'oscar',
'oscar.apps.catalogue',
'myproject.basket',
'oscar.apps.checkout',
'oscar.apps.order',
...
)
Same
app
label
as
parent
app
Friday, 20 July 12
Slide 46
Slide 46 text
# 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
Recap
•App
label
is
the
ID
•Models
can
overridden
and
extended
Friday, 20 July 12
Slide 49
Slide 49 text
from oscar.core.loading import get_class
OrderCreator = get_class('order.utils', 'OrderCreator')
Dynamic
loading
2
Friday, 20 July 12
Slide 50
Slide 50 text
# 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
Slide 51
Slide 51 text
Recap
•(App
module,
class
name)
is
the
ID
•Any
class
can
be
overridden
or
extended
Friday, 20 July 12
Slide 52
Slide 52 text
Tips
and
advice
Friday, 20 July 12
Slide 53
Slide 53 text
Log
everything
...except
sensitive
customer
details.
Friday, 20 July 12
Slide 54
Slide 54 text
Audit
models
Friday, 20 July 12
Slide 55
Slide 55 text
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
Slide 56
Slide 56 text
•High
and
low
thresholds
•It’s
always
your
fault
when
things
go
wrong
Monitor
everything
Friday, 20 July 12
Slide 57
Slide 57 text
Service
layers
•Avoid
views
talking
to
your
models
directly
•See
‘Facade’
design
pattern
•Anti-‐corruption
layers
Friday, 20 July 12
Slide 58
Slide 58 text
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
Slide 59
Slide 59 text
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
Slide 60
Slide 60 text
Image
credits
Books:
http://www.flickr.com/photos/th3ph17/3091294342/
Nail varnish:
http://www.flickr.com/photos/kqedquest/831547339/
T-shirts:
http://www.flickr.com/photos/blazerman/177165473/
Friday, 20 July 12