Upload
leliem
View
218
Download
2
Embed Size (px)
Citation preview
Me•David Winterbottom / @codeinthehole
•Tangent Labs, London
•Head of E-‐commerce team
•Python hacker
•commandlinefu.com, django-‐oscar
Friday, 20 July 12
Synopsis•Motivation
•Oscar -‐ what problem does it solve?
•Design decisions -‐ customisation techniques
•E-‐commerce tips/advice
Friday, 20 July 12
•5 years of e-‐commerce projects
•PHP => Python / Django
•Lots of war stories
Tangent Labs
Friday, 20 July 12
Bookshop domain•Millions of products
•ISBNs, BIC/BISAC categories, authors, publishers
•Automated feed-‐driven processing
•Catalogue
•Stock
•Rich data
Friday, 20 July 12
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
Variations•New fulfilment partners
•Stock/availability logic
•Multiple payment partners
•Split-‐payment sources
•Multibuy offers, vouchers
•eBooks!
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
New requirements•Product variations -‐ colours, sizes etc
•New fulfilment processes:
•webservices / warehouses
•Per-‐customer prices
Friday, 20 July 12
B2B•Sales reps, customer hierarchies
•Tax rules
•Managed budgets
•Integration with “enterprise” partners
Friday, 20 July 12
Requirements•Lean -‐ as few assumptions as possible
•Models domain
•without duplication
•without too much meta-‐data
Friday, 20 July 12
Domain modelling•Implementation deeply connected to core business concepts
•“...where powerful new features unfold as corollaries to older features.”
Friday, 20 July 12
Lots of others•Satchmo
•Lightning-‐Fast-‐Shop
•Satchless
•Django-‐shop
•Plata, Mamona, Cartridge, ...
•http://djangopackages.com/grids/g/ecommerce/
Friday, 20 July 12
Web framework
•Well-‐thought out structure
•Templating, HTTP, security, caching, ...
•Class-‐based views
Friday, 20 July 12
Models
•Models drive the design
•Capture domain logic
•Foundation for rest of application
Friday, 20 July 12
Eco-‐system•Haystack (search)
•South (database migrations)
•Celery (job queue)
•Internal libraries
Friday, 20 July 12
Different approach
•Key idea:
•Having the same name/identifier as your parent
•Subclass and override
Friday, 20 July 12
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader',)
TEMPLATE_DIRS = ( '/var/www/project/templates/',)
Replace
Friday, 20 July 12
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
# base.html
{% extends 'templates/base.html' %}
{% block scripts %}<script src="new.js" type="text/javascript"></script>{% endblock %}
Override
Friday, 20 July 12
# base.html
{% extends 'templates/base.html' %}
{% block scripts %}<script src="new.js" type="text/javascript"></script>{{ block.super }}{% endblock %}
Extend
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
from django.db.loading import get_model
Line = get_model('basket', 'Line')
Dynamic loading 1
INSTALLED_APPS = ( 'oscar.apps.basket')
Friday, 20 July 12
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', 'oscar.apps.basket', 'oscar.apps.checkout', 'oscar.apps.order', ...)
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
# 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
INSTALLED_APPS = ( 'oscar', 'oscar.apps.catalogue', 'oscar.apps.basket', 'oscar.apps.checkout', 'oscar.apps.order', ...)
templatetagsmanagement commands
Friday, 20 July 12
from oscar.core.loading import get_class
OrderCreator = get_class('order.utils', 'OrderCreator')
Dynamic loading 2
Friday, 20 July 12
# 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
Recap
•(App module, class name) is the ID
•Any class can be overridden or extended
Friday, 20 July 12
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
•High and low thresholds
•It’s always your fault when things go wrong
Monitor everything
Friday, 20 July 12
Service layers•Avoid views talking to your models directly
•See ‘Facade’ design pattern
•Anti-‐corruption layers
Friday, 20 July 12
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
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
Image creditsBooks: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