Slide 1

Slide 1 text

Demystifying Mixins with Django

Slide 2

Slide 2 text

@anabalica

Slide 3

Slide 3 text

I work at Potato

Slide 4

Slide 4 text

Mixins are a controlled way of adding functionality to classes.

Slide 5

Slide 5 text

Mixins are not special language constructs.

Slide 6

Slide 6 text

In fact, mixins are ordinary Python classes. 1 class SomeMixin(object): 2 """My smart mixin""" 3 4 def test_method(self): 5 pass

Slide 7

Slide 7 text

Why use mixins? to improve modularity

Slide 8

Slide 8 text

When to use mixins? want to reuse a particular feature in a lot of different classes

Slide 9

Slide 9 text

Properties • single responsibility • not meant to be extended • not meant to be instantiated

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

In Python the concept of mixins is implemented using multiple inheritance.

Slide 13

Slide 13 text

Order matters

Slide 14

Slide 14 text

1 class Foo(BaseFoo, SomeMixin): 2 pass

Slide 15

Slide 15 text

1 class Foo(BaseFoo, SomeMixin): 2 pass base class

Slide 16

Slide 16 text

1 class Foo(BaseFoo, SomeMixin): 2 pass base class mixin

Slide 17

Slide 17 text

1 class Foo(BaseFoo, SomeMixin): 2 pass

Slide 18

Slide 18 text

1 class Foo(SomeMixin, BaseFoo): 2 pass

Slide 19

Slide 19 text

1 class Foo(SomeMixin, BaseFoo): 2 pass

Slide 20

Slide 20 text

1 # some_app/views.py 2 from django.views.generic import TemplateView 3 4 5 class AboutView(TemplateView): 6 template_name = "about.html"

Slide 21

Slide 21 text

1 # some_app/views.py 2 from django.views.generic import TemplateView 3 4 5 class AboutView(SomeMixin, TemplateView): 6 template_name = "about.html"

Slide 22

Slide 22 text

1 # some_app/views.py 2 from django.views.generic import TemplateView 3 4 5 class AboutView(SomeMixin, TemplateView): 6 template_name = "about.html"

Slide 23

Slide 23 text

My first mixin

Slide 24

Slide 24 text

1 # some_app/views.py 2 3 4 class LoginRequiredMixin(object): 5

Slide 25

Slide 25 text

1 # some_app/views.py 2 3 4 class LoginRequiredMixin(object): 5 6 def dispatch(self, request, *args, **kwargs): 7

Slide 26

Slide 26 text

1 # some_app/views.py 2 from django.core.exceptions import PermissionDenied 3 4 5 class LoginRequiredMixin(object): 6 7 def dispatch(self, request, *args, **kwargs): 8 if not request.user.is_authenticated(): 9 raise PermissionDenied 10

Slide 27

Slide 27 text

1 # some_app/views.py 2 from django.core.exceptions import PermissionDenied 3 4 5 class LoginRequiredMixin(object): 6 7 def dispatch(self, request, *args, **kwargs): 8 if not request.user.is_authenticated(): 9 raise PermissionDenied 10 11 return super(LoginRequiredMixin, self).\ 12 dispatch(request, *args, **kwargs) 13

Slide 28

Slide 28 text

1 # some_app/views.py 2 from django.views.generic import TemplateView 3 4 5 class AboutView(LoginRequiredMixin, TemplateView): 6 template_name = "about.html"

Slide 29

Slide 29 text

LoginRequiredMixin TemplateView AboutView

Slide 30

Slide 30 text

LoginRequiredMixin DetailView AboutView

Slide 31

Slide 31 text

TemplateView LoginRequiredTemplateView AboutView ListView LoginRequiredListView AboutView CreateView LoginRequiredCreateView AboutView DetailView LoginRequiredDetailView AboutView FormView LoginRequiredFormView AboutView MyView LoginRequiredMyView AboutView

Slide 32

Slide 32 text

LoginRequiredMixin TemplateView AboutView

Slide 33

Slide 33 text

dispatch() get_context_data() get_template_names() check if user is logged in, has permission add new data to the context add more flexibility to the template names

Slide 34

Slide 34 text

1 # some_app/views.py 2 from django.views.generic import TemplateView 3 4 5 class AboutView(TemplateView): 6 template_name = "about.html"

Slide 35

Slide 35 text

dispatch() get_context_data() get_template_names() check if user is logged in, has permission add new data to the context add more flexibility to the template names

Slide 36

Slide 36 text

docs.djangoproject.com/en/1.8/ref/ class-based-views/base/

Slide 37

Slide 37 text

docs.djangoproject.com/en/1.8/ref/ class-based-views/base/

Slide 38

Slide 38 text

docs.djangoproject.com/en/1.8/topics/ class-based-views/mixins/

Slide 39

Slide 39 text

docs.djangoproject.com/en/1.8/topics/ class-based-views/mixins/

Slide 40

Slide 40 text

ccbv.co.uk/

Slide 41

Slide 41 text

django-braces Access Mixins Form Mixins Other Mixins

Slide 42

Slide 42 text

Decorators login_required() user_passes_test() permission_required()

Slide 43

Slide 43 text

Good news everyone!

Slide 44

Slide 44 text

Django 1.9 LoginRequiredMixin UserPassesTestMixin PermissionRequiredMixin

Slide 45

Slide 45 text

Runtime magic

Slide 46

Slide 46 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 py2

Slide 47

Slide 47 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 py2

Slide 48

Slide 48 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 10 11 if __name__ == '__main__': 12 domo = Mascot("Domo-kun") 13 Mascot.__bases__ += (CuteMixin, ) 14 domo.be_cute() py2

Slide 49

Slide 49 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 10 11 if __name__ == '__main__': 12 domo = Mascot("Domo-kun") 13 Mascot.__bases__ += (CuteMixin, ) 14 domo.be_cute() py2

Slide 50

Slide 50 text

Domo-kun ✿♥‿♥✿

Slide 51

Slide 51 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 10 11 if __name__ == '__main__': 12 domo = Mascot("Domo-kun") 13 Mascot.__bases__ += (CuteMixin, ) 14 domo.be_cute() py2

Slide 52

Slide 52 text

1 class CuteMixin: 2 def be_cute(self): 3 print(“{} ✿♥‿♥✿”.format(self.name)) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 py3

Slide 53

Slide 53 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 10 11 if __name__ == '__main__': 12 kumamon = Mascot("Kumamon") 13 kumamon.__class__ = type('SomeNewType', 14 (Mascot, CuteMixin), {}) 15 kumamon.be_cute() py3

Slide 54

Slide 54 text

1 class CuteMixin: 2 def be_cute(self): 3 print "{} ✿♥‿♥✿".format(self.name) 4 5 6 class Mascot: 7 def __init__(self, name): 8 self.name = name 9 10 11 if __name__ == '__main__': 12 kumamon = Mascot("Kumamon") 13 kumamon.__class__ = type('SomeNewType', 14 (Mascot, CuteMixin), {}) 15 kumamon.be_cute() py3

Slide 55

Slide 55 text

Kumamon ✿♥‿♥✿

Slide 56

Slide 56 text

With great power comes great responsibility

Slide 57

Slide 57 text

Recap • single responsibility • plug-in functionality • isn’t creating a subtyping relation

Slide 58

Slide 58 text

Go back to your views and start writing mixins to clean up the code.