Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Hunting for Treasure in Django

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.

Seb

September 07, 2015
Tweet

More Decks by Seb

Other Decks in Technology

Transcript

  1. Sebastian Vetter » Django & Python Developer » Backend Engineer

    @ Mobify in Vancouver ! » @elbaschid on github & twitter » Slides: http://bit.ly/treasure-hunt
  2. Awesome Django Features » Forms, » Views, » Models, »

    the ORM, or » other commonly used APIs.
  3. What Does That Mean? » Useful pieces of Django code.

    » Considered public API. » Documentation is available (sort of). » Mainly used within Django itself.
  4. Where You Find Them » Digging through the Django source.

    » Working with great & smart people. » Hanging out in the IRC channel. » Sprinting at Conferences.
  5. What It Does » It's a decorator. » Caches property's

    return value. » Lives as long as the instance.
  6. Where It Is Useful » Compute-heavy properties on a class.

    » Calling web APIs. » Property used more than once.
  7. 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)
  8. Here's the problem >>> c = Color('ffffff') >>> c.name Requesting

    #ffffff white >>> c.name Requesting #ffffff white
  9. You Can DIY it @property def name(self): if self._name is

    None: self._name = self._request_colour_name(self.hex) return self._name
  10. 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)
  11. Using the cached property >>> c = Color('ffffff') >>> c.name

    Requesting #ffffff white >>> c.name white
  12. Beware Of Querysets » Be careful with querysets. class VeryComplicatedView(object):

    @cached_property def get_followers(self): return User.objects.filter(followed_by=self.user)
  13. What It Does » Takes dotted path to a class

    or function. » Validates and loads it. » Returns the class or function object.
  14. 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]>
  15. Where It Is Useful » Make a class or function

    configurable. » Custom implementation in libraries.
  16. Imagine A Web Store » Products have a "slug". »

    But you want it to be customizable. # settings.py CUSTOM_SLUG_FUNCTION = 'my_store.!"#$_slugifier'
  17. 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)
  18. 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
  19. What It Does » Delays execution of the wrapped callable.

    » Used for the Django settings module.
  20. Where It Is Useful » Accessing settings at parse time.

    » Translating strings outside of a view. » Translations in the settings module.
  21. What It Looks Like from django.utils.functional import lazy from django.core.urlresolvers

    import reverse reverse_lazy = lazy(reverse('home'), unicode))
  22. 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) ...
  23. 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
  24. What It Does » Takes a URL with a HTTP

    method. » Creates an actual Request object.
  25. 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) ...
  26. 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
  27. Where It Is Useful » Use function decorators on views.

    » Decorate dispatch on a view without extending it.
  28. 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)
  29. 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