Hunting for Treasure in Django

C65d18a43152b199ee94aad2b79b70c4?s=47 Seb
September 07, 2015

Hunting for Treasure in Django

We all use Django because it is a framework that simplifies the development of our web apps by providing an implementation of common patterns. Additionally, it also provides a lot of helpers around these implementations that simply our lives even more. This talk will investigate the "hidden" treasures of decorators and functions in Django's core.

C65d18a43152b199ee94aad2b79b70c4?s=128

Seb

September 07, 2015
Tweet

Transcript

  1. 2.

    Sebastian Vetter » Django & Python Developer » Backend Engineer

    @ Mobify in Vancouver ! » @elbaschid on github & twitter » Slides: http://bit.ly/treasure-hunt
  2. 4.

    Awesome Django Features » Forms, » Views, » Models, »

    the ORM, or » other commonly used APIs.
  3. 7.

    What Does That Mean? » Useful pieces of Django code.

    » Considered public API. » Documentation is available (sort of). » Mainly used within Django itself.
  4. 9.

    Where You Find Them » Digging through the Django source.

    » Working with great & smart people. » Hanging out in the IRC channel. » Sprinting at Conferences.
  5. 10.
  6. 12.

    What It Does » It's a decorator. » Caches property's

    return value. » Lives as long as the instance.
  7. 14.

    Where It Is Useful » Compute-heavy properties on a class.

    » Calling web APIs. » Property used more than once.
  8. 15.

    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)
  9. 16.

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

    #ffffff white >>> c.name Requesting #ffffff white
  10. 17.

    You Can DIY it @property def name(self): if self._name is

    None: self._name = self._request_colour_name(self.hex) return self._name
  11. 18.

    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)
  12. 19.

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

    Requesting #ffffff white >>> c.name white
  13. 20.

    Beware Of Querysets » Be careful with querysets. class VeryComplicatedView(object):

    @cached_property def get_followers(self): return User.objects.filter(followed_by=self.user)
  14. 24.

    What It Does » Takes dotted path to a class

    or function. » Validates and loads it. » Returns the class or function object.
  15. 25.

    What It Looks Like from django.utils.module_loading import import_string get_func =

    import_string('requests.get') print get_func ## <function requests.api.get> get_func('https://google.ca') ## <Response [200]>
  16. 26.

    Where It Is Useful » Make a class or function

    configurable. » Custom implementation in libraries.
  17. 27.

    Imagine A Web Store » Products have a "slug". »

    But you want it to be customizable. # settings.py CUSTOM_SLUG_FUNCTION = 'my_store.!"#$_slugifier'
  18. 28.

    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)
  19. 29.

    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
  20. 32.

    What It Does » Delays execution of the wrapped callable.

    » Used for the Django settings module.
  21. 33.

    Where It Is Useful » Accessing settings at parse time.

    » Translating strings outside of a view. » Translations in the settings module.
  22. 34.

    What It Looks Like from django.utils.functional import lazy from django.core.urlresolvers

    import reverse reverse_lazy = lazy(reverse('home'), unicode))
  23. 36.
  24. 37.

    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) ...
  25. 38.

    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
  26. 41.

    What It Does » Takes a URL with a HTTP

    method. » Creates an actual Request object.
  27. 45.

    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) ...
  28. 46.

    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
  29. 51.

    Where It Is Useful » Use function decorators on views.

    » Decorate dispatch on a view without extending it.
  30. 52.

    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)
  31. 57.

    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