Learning Design Patterns from django
github.com/geeknam
ABOUT
Developer
Kogan donates $10k to DSF
WE ARE HIRING !!!
DJANGo philosophies
DJANGO design pattern examples
SIMPLE EXAMPLES
USE CASES
WHY DO WE CARE?
Django PHILOSOPHIES
Loose COUPLING
LESS CODE
QUICK DEVELOPMENT
DRY
CONSISTENCY
DJANGO ORM
Developer.objects.filter(
city='Melbourne', language='python', framework='Django'
)
LESS CODE
QUICK DEVELOPMENT
Example
Quick & dirty
import requests
url = '.../api/product/?department=televisions&order_by=price'
data = requests.get(url).json()
objects = data['objects']
for object in objects:
...
WHY NOT?
Product.objects.filter(department='televisions'
).filter(category='led-tv').order_by('price')
Chain methods
MAKE THEM LAZY
CACHE RESULTS
Return Objects
USE cases
Querying REST API
Querying external services
Client libraries
django-haystack
MIDDLEWARE & CONTEXT PROCESSORS
MIDDLEWARE_CLASSES = (
'django.middleware.gzip.GZipMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.request",
)
Loose coupling
Plugable
Example
Email Validator
email = 'sOmeEmail@MelbDjango.com'
def validate_email(email):
if '@' not in email:
raise ValidationError('Invalid email. @ not found')
if '.' not in email:
raise ValidationError('Invalid email. Incorrect domain?')
# lowercase domain
name, domain = email.split('@')
email = '@'.join([name, domain.lower()])
WE can do it this way
PIPELINE = (
'validation.contains_dot',
'validation.contains_at',
'mutators.lowercase_domain',
'mutators.lowercase_name',
)
email = EmailValidator('sOmeEmail@MelbDjango.com').email
print email
> 'someemail@melbdjango.com'
PIPELINES
IMPORT MODULES
Use CASES
MIXINS (CBV)
class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
pass
LESS CODE
REUSABLE
Example
class Price(object):
def __init__(self, amount):
self.amount = amount
class Discount(object):
def __init__(self, amount, expiry_date=None):
self.amount = amount
if expiry_date:
self.expiry_date = expiry_date
else:
self.expiry_date = datetime.now()
@property
def expired(self):
return self.expiry_date < datetime.now()
They are comparable
class ComparableMixin(object):
def __lt__(self, other):
return self.amount < other.amount
def __eq__(self, other):
return self.amount == other.amount
def __gt__(self, other):
return self.amount > other.amount
def __ne__(self, other):
return self.amount != other.amount
BEWARE !!!
Method resolution order
LEFT > RIGHT
Meta OPTIOns
class Developer(models.Model):
...
class Meta:
verbose_name_plural = 'Monkeys'
permissions = (
('can_code', 'Can smash the keyboard')
)
METACLASS
EXAMPLE
@receiver(post_save, sender=Developer) def do_something(sender, instance=None, **kwargs): ... @receiver(pre_delete, sender=Developer) def do_something_else(sender, instance=None, **kwargs): ...
@receiver(drinks_coffee, sender=Developer) def max_focus(sender, instance=None, **kwargs): ...
@receiver(reads_hacker_news, sender=Developer) def min_focus(sender, instance=None, **kwargs):
...
Add some magic
class DeveloperObserver(ModelObserver):
class Meta:
model = Developer
def post_save_receiver(self, instance, **kwargs):
...
def drinks_coffee_receiver(self, instance, **kwargs):
...
def reads_hacker_news_receiver(self, instance, **kwargs):
...
USE cases
django-rest-framework
django-tastypie
django-nap
many more...
inspired by...
Django
learnt something new today?
we're hiring
Learning Design Patterns from django
By Nam Ngo
Learning Design Patterns from django
- 848