Slide 1

Slide 1 text

Hunting for Treasure in Django Sebastian Vetter @elbaschid

Slide 2

Slide 2 text

Sebastian Vetter » Django & Python Developer » Backend Engineer @ Mobify in Vancouver ! » @elbaschid on github & twitter » Slides: http://bit.ly/treasure-hunt

Slide 3

Slide 3 text

Let's Find Some Treasure

Slide 4

Slide 4 text

Awesome Django Features » Forms, » Views, » Models, » the ORM, or » other commonly used APIs.

Slide 5

Slide 5 text

An Old Hat

Slide 6

Slide 6 text

Hidden Treasures

Slide 7

Slide 7 text

What Does That Mean? » Useful pieces of Django code. » Considered public API. » Documentation is available (sort of). » Mainly used within Django itself.

Slide 8

Slide 8 text

Where To Find Them

Slide 9

Slide 9 text

Where You Find Them » Digging through the Django source. » Working with great & smart people. » Hanging out in the IRC channel. » Sprinting at Conferences.

Slide 10

Slide 10 text

Ready?

Slide 11

Slide 11 text

cached_property

Slide 12

Slide 12 text

What It Does » It's a decorator. » Caches property's return value. » Lives as long as the instance.

Slide 13

Slide 13 text

What It Looks Like class MyObject(object): @cached_property def compute_heavy_method(self): ... return result

Slide 14

Slide 14 text

Where It Is Useful » Compute-heavy properties on a class. » Calling web APIs. » Property used more than once.

Slide 15

Slide 15 text

Imagine A Color API class Color(object): def __init__(self, hex): self.hex = hex def _request_colour_name(self, hex): print "Requesting #{}".format(hex) rsp = requests.get(API_ENDPOINT.format(hex)) return rsp.json()[0].get("title") @property def name(self): return self._request_colour_name(self.hex)

Slide 16

Slide 16 text

Here's the problem >>> c = Color('ffffff') >>> c.name Requesting #ffffff white >>> c.name Requesting #ffffff white

Slide 17

Slide 17 text

You Can DIY it @property def name(self): if self._name is None: self._name = self._request_colour_name(self.hex) return self._name

Slide 18

Slide 18 text

Or Use cached_property from django.utils.functional import cached_property class Some(object): ... @cached_property def name(self): return self._request_colour_name(self.hex)

Slide 19

Slide 19 text

Using the cached property >>> c = Color('ffffff') >>> c.name Requesting #ffffff white >>> c.name white

Slide 20

Slide 20 text

Beware Of Querysets » Be careful with querysets. class VeryComplicatedView(object): @cached_property def get_followers(self): return User.objects.filter(followed_by=self.user)

Slide 21

Slide 21 text

In Short from django.utils.functional import cached_property » Django docs » Source

Slide 22

Slide 22 text

Treasure Found

Slide 23

Slide 23 text

import_string

Slide 24

Slide 24 text

What It Does » Takes dotted path to a class or function. » Validates and loads it. » Returns the class or function object.

Slide 25

Slide 25 text

What It Looks Like from django.utils.module_loading import import_string get_func = import_string('requests.get') print get_func ## get_func('https://google.ca') ##

Slide 26

Slide 26 text

Where It Is Useful » Make a class or function configurable. » Custom implementation in libraries.

Slide 27

Slide 27 text

Imagine A Web Store » Products have a "slug". » But you want it to be customizable. # settings.py CUSTOM_SLUG_FUNCTION = 'my_store.!"#$_slugifier'

Slide 28

Slide 28 text

Slugify Is Easy Now # utils.py def slugify(value): slugifier = getattr(settings, 'CUSTOM_SLUG_FUNCTION', DEFAULT_SLUG_FUNCTION) slugifier = import_string(slugifier) return slugifier(value)

Slide 29

Slide 29 text

In Short from django.utils.module_loading import import_string » Imports a class or function from a dotted path. » Previously known as import_by_path. » Django docs » Source

Slide 30

Slide 30 text

More Treasure

Slide 31

Slide 31 text

lazy & LazyObject

Slide 32

Slide 32 text

What It Does » Delays execution of the wrapped callable. » Used for the Django settings module.

Slide 33

Slide 33 text

Where It Is Useful » Accessing settings at parse time. » Translating strings outside of a view. » Translations in the settings module.

Slide 34

Slide 34 text

What It Looks Like from django.utils.functional import lazy from django.core.urlresolvers import reverse reverse_lazy = lazy(reverse('home'), unicode))

Slide 35

Slide 35 text

Imagine per-User Storage class PrivateMediaStorage(S3Storage): ... class AwesomeThing(models.Model): file = models.FileField(..., storage=PrivateMediaStorage()) ...

Slide 36

Slide 36 text

Kaboom

Slide 37

Slide 37 text

lazy To The Rescue def get_private_storage(): return PrivateMediaStorage() private_storage = SimpleLazyObject(get_private_storage) class AwesomeThing(models.Model): file = models.FileField(..., storage=private_storage) ...

Slide 38

Slide 38 text

In Short from django.utils.functional import lazy from django.utils.functional import SimpleLazyObject » Acts as a proxy class or function. » Delays execution of the wrapped object. » Django docs » Source

Slide 39

Slide 39 text

And Even More Treasure

Slide 40

Slide 40 text

RequestFactory

Slide 41

Slide 41 text

What It Does » Takes a URL with a HTTP method. » Creates an actual Request object.

Slide 42

Slide 42 text

What It Looks Like from django.test import RequestFactory request = RequestFactory().get('/some/path')

Slide 43

Slide 43 text

Where It Is Useful » Testing request-related code. » Mocking will be too much work.

Slide 44

Slide 44 text

Imagine A Middleware class SomeMiddleware(object): def process_request(self, request): ...

Slide 45

Slide 45 text

How To Test It from django.test import RequestFactory def test_processing_requests(): factory = RequestFactory() query_params = {"token": "secret-token"} request = RequestFactory().get('/some/path', data=query_params) SomeMiddleware.process_request(request) ...

Slide 46

Slide 46 text

In Short from django.test import RequestFactory » Creates a fake request for given URL. » Can handle all HTTP methods. » Will save you some mocking work. » Django docs » Source

Slide 47

Slide 47 text

Treasure Found

Slide 48

Slide 48 text

method_decorator

Slide 49

Slide 49 text

What It Does » It's another decorator. » Apply decorators to methods.

Slide 50

Slide 50 text

What It Looks Like class AboutPage(TemplateView): @method_decorator(function_decorator) def dispatch(self, request, *args, **kwargs): ...

Slide 51

Slide 51 text

Where It Is Useful » Use function decorators on views. » Decorate dispatch on a view without extending it.

Slide 52

Slide 52 text

What It Looks Like from waffle.decorators import waffle_flag class NewFeatureView(TemplateView): ... @method_decorator(waffle_flag('new-feature')) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs)

Slide 53

Slide 53 text

Or Like This from waffle.decorators import waffle_flag @method_decorator(waffle_flag('new-feature'), name='dispatch') class NewFeatureView(TemplateView): ...

Slide 54

Slide 54 text

In Short from django.utils.functional import method_decorator » Django docs » Source

Slide 55

Slide 55 text

The Treasure Is All Yours

Slide 56

Slide 56 text

Any Questions? » @elbaschid Slides: http://bit.ly/treasure-hunt

Slide 57

Slide 57 text

References (I) » https://www.flickr.com/photos/kohlerfolk/ 2189799465 » https://www.flickr.com/photos/ 28912254@N04/16532668296/ » https://www.flickr.com/photos/bernatcg/1123973353/ » https://flic.kr/p/93mN4L » https://www.flickr.com/photos/ 8015956@N04/10012870693/ » http://wallpapercave.com/wp/prPWzge.jpg

Slide 58

Slide 58 text

References (II) » https://www.flickr.com/photos/vandinglewop/ 6104500070/ » https://www.flickr.com/photos/xtrah/5005443977 » https://www.flickr.com/photos/chezpitch/ 6703950199/ » https://flic.kr/p/9qy7dG » https://www.flickr.com/photos/epsos/8463683689