Slide 1

Slide 1 text

Hunting for Treasure in Django Sebastian Vetter @elbaschid

Slide 2

Slide 2 text

Who Am I?

Slide 3

Slide 3 text

Sebastian • Django & Python Developer • Backend Engineer @ Mobify • github/twitter: elbaschid

Slide 4

Slide 4 text

What's The Treasure?

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

But They Are Boring

Slide 7

Slide 7 text

Real Treasure

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

My Hunting Strategy • Digging through the Django source. • Hanging out with Funkybob. • Learning from other great people.

Slide 10

Slide 10 text

What I'll Do • Show a few "hidden" treasures. • Explain what they do. • Look at examples.

Slide 11

Slide 11 text

cached_property

Slide 12

Slide 12 text

Where is it useful? • Time or compute heavy properties on a class. • Synchronous calls to remote servers. • Used more than once, e.g. code & template.

Slide 13

Slide 13 text

What does it do? • It's a decorator. • Caches the return value. • Lives as long as the instance.

Slide 14

Slide 14 text

It looks like this class MyObject(object): @cached_property def compute_heavy_method(self): ... return result

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 • Using the name attribute will call the API • Every time!

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Possible solution @property def name(self): if self._name is None: self._name = self._request_colour_name(self.hex) return self._name

Slide 19

Slide 19 text

Or you can use cached_property from django.utils.functional import cached_property @cached_property def name(self): return self._request_colour_name(self.hex)

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Isn't That Great

Slide 22

Slide 22 text

All you Need To Know from django.utils.functional import cached_property • Only cached for the lifetime of the instance. • Be careful with querysets. • Django docs • Source

Slide 23

Slide 23 text

import_string

Slide 24

Slide 24 text

Where is it useful? • Make a class or function configurable. • Allow loading class/function from string.

Slide 25

Slide 25 text

What does it do? • Takes dotted path to a class or function. • Loads it. • Returns the class or function object.

Slide 26

Slide 26 text

It looks like this from django.utils.module_loading import import_string get_func = import_string('requests.get') print get_func # get_func('https://google.ca') #

Slide 27

Slide 27 text

# settings.py UPLOAD_VALIDATION_PIPELINE = [ 'my_project.uploads.validators.is_tarball', 'my_project.uploads.validators.has_readme_file', 'my_project.uploads.validators.has_no_!']

Slide 28

Slide 28 text

All you Need To Know from django.utils.module_loading import import_string • Imports a class or function from a dotted path. • Django docs • Source

Slide 29

Slide 29 text

lazy and lazy_property

Slide 30

Slide 30 text

Where is it useful? • Accessing settings at parse time, e.g. class attributes. • Translating strings outside of a view. • Translations in the settings module.

Slide 31

Slide 31 text

Here's a problem class UserSignupView(CreateView): ... success_url = reverse('signup-confirmed')

Slide 32

Slide 32 text

How can we fix it? from django.utils.functional import lazy class UserSignupView(CreateView): ... success_url = lazy(reverse('signup-confirmed'), unicode)

Slide 33

Slide 33 text

Lazy Django • The Settings object is lazy. • Several helpers have lazy siblings: • reverse_lazy • ugettext_lazy • Not sure what lazy_property is useful for.

Slide 34

Slide 34 text

All you Need To Know from django.utils.functional import lazy from django.utils.functional import SimpleLazyObject • Imports a class or function from a dotted path. • Django docs • Source

Slide 35

Slide 35 text

RequestFactory

Slide 36

Slide 36 text

Where Is It Useful? • Testing request related code. • Mocking will be too much work. • Using the test client doesn't make sense.

Slide 37

Slide 37 text

Create GET Request from django.test import RequestFactory request = RequestFactory().get('/some/path') # with a query string query_params = {"token": "secret-token"} request = RequestFactory().get('/some/path', data=query_params)

Slide 38

Slide 38 text

Create POST Request from django.test import RequestFactory post_params = {'username':'testuser', 'password':'supersecret'} request = RequestFactory().post('/login', data=post_params)

Slide 39

Slide 39 text

All you Need To Know 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 40

Slide 40 text

The Treasure Is Yours

Slide 41

Slide 41 text

Thanks! Questions? • www.roadsi.de • @elbaschid • github.com/elbaschid Slides: https://speakerdeck.com/elbaschid