Demystifying Mixins with Django
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Part Number | 8 | |
Number of Parts | 173 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/20072 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Production Place | Bilbao, Euskadi, Spain |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
| |
Keywords |
EuroPython 20158 / 173
5
6
7
9
21
27
30
32
36
37
41
43
44
45
47
51
52
54
55
58
63
66
67
68
69
72
74
75
77
79
82
89
92
93
96
97
98
99
101
104
108
111
112
119
121
122
123
131
134
137
138
139
150
160
165
167
173
00:00
Context awarenessSoftware frameworkTwitterTouch typingLecture/Conference
00:46
Game controllerFunctional (mathematics)QuicksortMobile appRight angleAbsolute valueSocial classFormal languageConstructor (object-oriented programming)Point (geometry)Computer animation
01:13
PlastikkarteSocial classSoftware testingMountain passSingle-precision floating-point formatOrder (biology)Core dumpInheritance (object-oriented programming)LogarithmMetropolitan area networkView (database)Inheritance (object-oriented programming)LoginMultiplication signSocial classFactory (trading post)Line (geometry)Different (Kate Ryan album)Web pageNumberDependent and independent variablesException handlingAbstractionCASE <Informatik>InformationElectronic signatureGroup actionTemplate (C++)Java appletObject (grammar)Web-DesignerProjective planeTask (computing)Goodness of fitMaxima and minimaOrder (biology)CodeArrow of timeRight angleEncapsulation (object-oriented programming)MathematicsModul <Datentyp>MultiplicationSoftware frameworkSound effectMixed realityCore dumpInfinityMetropolitan area networkTheory of relativityMoment (mathematics)WordSlide ruleInternet service providerBitCondition numberGenderSingle-precision floating-point formatPoint (geometry)Graph coloringComplete metric spaceGreen's functionXML
09:13
Social classMaxima and minimaMassDensity of statesJava appletLogarithmMetropolitan area networkData typePower (physics)AngleSingle-precision floating-point formatFinitary relationDiagramBitView (database)Functional (mathematics)Letterpress printingVideo gameAttribute grammarStatement (computer science)NumberSocial classDifferent (Kate Ryan album)FreewareMilitary baseObject (grammar)Mixed realityWordCASE <Informatik>Latent heatLoginLine (geometry)Type theoryReal numberDataflowCodierung <Programmierung>Context awarenessDependent and independent variablesData structureInternet service providerBasis <Mathematik>Goodness of fitPower (physics)Source codeHierarchyMathematicsCodeDisk read-and-write headInstance (computer science)Auditory maskingMultiplication signPrincipal idealForm (programming)Solid geometrySimilarity (geometry)Task (computing)Category of beingTheory of relativityInheritance (object-oriented programming)2 (number)Game controllerLogicProjective planeMechanism designVolumenvisualisierungMassParameter (computer programming)Run time (program lifecycle phase)Level (video gaming)Acoustic shadowPlug-in (computing)Revision controlSoftware testingChainDynamical systemUniform resource locatorLecture/ConferenceComputer animationXML
17:39
CodeCodeComputer animation
18:01
Functional (mathematics)Context awarenessEndliche ModelltheorieBitView (database)Social classSet (mathematics)Data structurePoint (geometry)CASE <Informatik>Core dumpCodeDifferent (Kate Ryan album)Theory of relativitySource codeAttribute grammarDataflowFlow separationNumberLoginInheritance (object-oriented programming)Form (programming)Meta elementConnectivity (graph theory)Incidence algebraLogicLinearizationModule (mathematics)Moment (mathematics)Mixed realityProcess (computing)Decision theoryFault-tolerant systemQuicksortIterationMaxima and minimaLecture/Conference
Transcript: English(auto-generated)
00:07
Voila, everyone. I'm really excited to be at EuroPython this year, and I'm really glad so many of you made it to this talk, because it's Friday, so yay, cool. So demystifying mixins with Django is somewhat of an opinionated talk,
00:22
and it's going to be about understanding what are mixins, how they work, and how to create your own mixins in the context of Django framework. I'll be glad to answer all your questions by the end of this talk. So, my name is Anna, and the simplest way
00:41
to get in touch with me is via Twitter. I work at Potato, and I absolutely love saying this sentence, but seriously, Potato is an amazing company where we create all sorts of apps with Django and not only. Let's dive right in. Mixins are a controlled way of adding functionality to classes.
01:02
But mixins are not special language constructs. This means there is no special keyword in Python that will point to some construct and say, well, this is a mixin. In fact, mixins are just ordinary Python classes. Take a look at this short example. It is a class called SomeMixin,
01:22
and it has one method that does nothing. Well, this is a useless mixin for obvious reasons, but let me draw your attention to one important bit over here. Our little mixin inherits from object, and only from object, if we are using new style Python classes.
01:40
So, the takeaway from here is that mixins are preferably not derived classes. Mixins offer modularity, and that's the main reason we want to use them. When to use them? Well, when we want to reuse a particular feature in a lot of different classes, especially when this feature doesn't belong
02:01
in any of the existing classes. That's why mixins should be narrow in scope. In other words, have one single responsibility. They're not meant to be extended, and they're not meant to be instantiated. I mentioned mixins are good in creating modular designs,
02:20
so let's take a closer look at this decoupling concept. Imagine that you have an encapsulator that has four color-coded features, orange, blue, green, and yellow. So far, so good. Imagine over time that your project grows bigger, and we create new classes that encapsulate their own features.
02:41
At this point, this code smells. It's ugly. There is something wrong with all those four classes, because this yellow feature appears in all four of them. I bet someone copy-pasted it. So, what we need to do in this case is to extract the yellow feature and put it in a separate encapsulator
03:02
so that the current and future classes can benefit from our newly created mixin. And here comes the question, how do we actually do that? Well, in Python and not only, the concept of mixins is implemented using multiple inheritance. And when we talk about multiple inheritance in Python,
03:23
the order of inheritance matters. Here's how we can use a mixin. Say we have a class foo that inherits from base foo and some mixin. You might think, especially according to some naming conventions, that base foo acts as a base class,
03:40
and some mixin is indeed a mixin. Nevertheless, we should be reading this code in the following manner. Some mixin is a base class extended by base foo, extended by foo. This might not be a problem if some mixin and base foo are not sharing, extending, or overriding any of the existing methods.
04:04
But if you are conscious that some mixin will be extending a method of base foo, you should reverse the order. Well, that looks much better to me. An easy way to remember Python inheritance order is with one single arrow that goes all the way from right to left.
04:22
When you start chaining mixins, be especially careful about your order. Who has heard about this thing, like framework, Django, someone, hmm, someone, yeah? Grows in popularity, I think.
04:42
Who has ever used class-based views? That's more like a lot of people. But if you didn't, that's no problem. I'll give you a short intro, really short. So here's a snippet, snippet, snippet, okay. Here's a snippet from the official Django documentation. It is a class-based view
05:01
that inherits from template view. And a template view helps us render a template. That's all it does. And all it asks from us is to configure the name of the template. Class-based views in Django is one typical use case where mixins use, where mixins feel very natural.
05:21
And so we're interested in plugging in over there a mixin. Yay, we know two things right now. We know what are mixins and how to use them. So let's go ahead and write our own first mixin. A common use case in web development is to protect some of our pages.
05:41
So we want to enforce our end users to authenticate before accessing a page. Let's create a mixin that will check if a user is authenticated. First thing we do, we choose a good class name, login required mixin. It inherits from object and we place it inside some app, views.py file, though it might be placed almost anywhere.
06:04
We would like to check if the user is authenticated before we start processing the request. You might know that or might not know that, but one of the first methods to be called when processing a request is dispatch. We use the same signature of the dispatch method as in the base view class.
06:22
And now it's time to do the proper check. So if you take a look at the lines eight and nine, we say if the user is not authenticated, raise a permission denied exception. And since we don't write any Java and there is no way to auto import packages, let's go ahead and specify on the line number two
06:40
that we import permission denied from Django Core exceptions. One last thing to do is to handle the use case when a user is actually authenticated and we want to allow him or her to access the ultimate page. Therefore, let's call the super method on dispatch and resume the work of the base method.
07:00
I leave it up to you to provide docs and tasks. Please do that. So going back to our about view, we plug in the login required mixin and ta-da, it works just like that. Now all the anonymous users are not allowed to trespass to the land of the super secret information of the about view.
07:21
And that's all there is required to protect a view. It's a very trivial example and very simplified, but it demonstrates a mixin in action. Here's how we describe graphically our latest usage of a mixin. The about view inherits both from template view and from login required mixin.
07:41
And if you ever decide, oh well, I want a detail view instead of a template view, well, no problem. And if you didn't see what a hell change on the slide, it's basically I have swapped the template view with the detail view. And that's a good thing, right? Because minimum effort is required to use a different view
08:00
with no additional cost. And this looks simple. At least I hope it does to you, does it? Yeah? So I'm preaching here how neat are those mixins, but what if there is a different way? There are tons of different ways, but there aren't necessarily good or the best.
08:21
So this made me think, how would I do it another way? I might check if the user is authenticated right in my view, but that's a stupid idea for obvious reasons. So I came up with this. As you will see also, there is stupid idea. So I extended the template view and created a new class
08:40
called Logging Required Template View. Starts to remind me of some abstract Oof factory view factory. And I made about view to inherit from it. Doesn't look that bad at the moment, but it actually does because every single other view, the number of which I extrapolate to infinity, that you want to have an Oof check
09:01
will be extended the same way. That's exactly the same problem we have discussed at the beginning. We didn't solve anything. We just continued to copy paste the Oof check everywhere. Now, take a look again at this diagram. It's elegant and simple. All right, so we all agree that mixins are fantastic.
09:23
How about looking a bit more inside class-based views and some common class-based views methods? If we want to add a feature to a class-based view using a mixin, we sometimes need to know a bit about the Django internals.
09:40
Once a request hits the template view, one of the first methods to be called is dispatch. We had this one. It figures out which HTTP method to call. Is it a get, is it a post? So it is useful to override dispatch to provide a check very early on before anything else happens to the request.
10:01
For example, check if the user is logged in or has permission. The next method, getContextData, is also sometimes useful to be overridden. It passes keyword arguments to the template context and so it is a way to add extra context to the views.
10:21
Next one, getTemplateNames, is a method called by render to response and it lists all template names. So it can be extended to add more flexibility to the template names if you have a different mechanism of identifying those in your Django project. So by now you probably should be angrily asking me
10:42
how do I know all that? Because all I showed you was this simple example with the template view and it looked neat. But then suddenly you need to know all of this. Well, I'd be angry too. So here are some ways how you can learn more about Django class-based views.
11:01
So my personal approach is to go, to jump right into the source code and it's easy to get your head around Django source code because it has docstrings and it's pretty well structured. But then of course there is a different approach. You can start with Django documentation to read a bit more about base classes
11:22
of class-based views and not by accident. Django uses mixins to build the class-based views and you can read about them at this URL. Again, I highly recommend to take a look at the Django class-based views and mixins source code because if you can't really wrap your head
11:44
around all those mixins, Django provides an example how to get started. This little website, ccbv.co.uk, is an awesome resource. It aggregates in one single place all the class-based views, their methods,
12:01
where they come from, their hierarchy diagrams and source code. So it's really good and well structured. I made you go through all of this login required mixin code but in real life, probably you don't bother implementing your own login required unless you really need to,
12:21
you have a specific use case. Basically because you have Django braces. Django braces is a package that aggregates common mixins that you will need in your project and they're structured in three categories, access, form and other mixins.
12:42
If you have been using Django for some time, you're probably familiar with those decorators. Login required, user passes test, and permission required. Well, I wish we had something similar in Django for class-based views.
13:01
Well, good news everyone. In Django 1.9, we will get login required mixin, user passes test mixin, and permission required mixin. Yay. According to the roadmap, the final 1.9 version will be released sometime in December
13:21
and those free mixins that shadow the original Django decorators were written during the Ciro's DjangoCon Europe sprints in the evening after I gave this little talk, so that's pretty cool. Someone was listening to the talk while I was babbling on the stage.
13:42
Now let's get a bit more evil. How about some runtime magic? So what I wanna do, I wanna plug in some behavior to my classes in the runtime dynamically. I personally never had a use case where I would need that, but let's try it just for fun.
14:02
Let me tell you a story. This is a cute mixin and the mixin assumes that we have a name attribute and what it does is one ordinary print statement. Oh yeah, so you can see this is Python 2. And now let's introduce Mr. Mascot and its name attribute.
14:22
One extra class, one attribute, fairly simple. Now we enter the land of Maine to bring to life some of our classes. So on line number 12, we create an instance of the mascot and his name is Domo. The next line is the magic.
14:43
It modifies the basis of the mascot class and adds the cute mixin to it. We are mixing it dynamically. Then we try to call the be cute method from the cute mixin on previously instantiated object and it works. Hey, meet Domo-kun.
15:03
I emphasize that this works in Python 2 and we are also using old style classes. I'm not inheriting from object. So basis was mutable back then, spooky story. How about now? How about if we are using Python 3
15:21
or we have new style classes? Isn't much of a difference in code? Well, the print is a function. Let's see what we can do. Well, we can't screw up as much as with Python 2 because basis is immutable. But we can change the dunder class attribute
15:43
on an instance that we have called kumamon and create a new type that includes the cute mixin and then make use of the be cute method. And this will work. If you ever do this, please make sure you do this for a very good reason
16:03
and please provide plenty of documentation explaining the why and I have warned you. Be careful when you decide to use mixins because with great power comes great responsibility. Beware of incompatible mixins,
16:22
chaining too many mixins and overdoing mixins, hence making it a nightmare to figure out the execution flow. Same as we advise against 100 lines long views functions and tons of decorators on your functions. We also advise against class-based views
16:41
that require six mixins to work. You're probably doing something wrong and placing too much logic into your view layer or controller layer. So let's recap what we have learned so far. Mixins in Python are classes and should have one single responsibility.
17:02
Semantically, we think about mixins as some plug-in reusable functionality. Although mixins are mixed in using inheritance, they're not creating a subtyping relation. This means they don't adhere to Liskov principle from Solid.
17:21
Liskov principle says the following, instances of base class can be replaced with instances of derived classes and it will make sense. This statement doesn't hold for mixins and that's why we say that mixins are not creating a subtyping relation. I hope I convinced you that mixins
17:42
are pretty cool and easy to create. Therefore, I strongly encourage you to go back to your views and start creating mixins to clean up your code. Thank you.
18:08
So if you want, ah, there you go. Have you got any question? Well, I've got one to start with anyway. You say six mixins is too much for a view,
18:21
but what about three of them? Is this still okay? It depends on your use case. Normally, you would have two mixins is quite okay because you probably need a login required and then it has permission, quite a common use case. Maybe you have an extra one, it's still going to be fine
18:41
but the harder it gets to figure out where your request flows. So in this case, I think there are kind of like the couple because you log in, you know what it's doing and it has permission. They both work with the dispatch and then you have an extra mixin that changes something in your context.
19:01
Might be okay. So three is still fine. Okay. And four might be pushing it. Yes. Okay. Any more questions? Yes, at the back.
19:27
And what if you want to combine the functionality of several mixins? What's the recommended way? Like extending mixins, subclassing mixins or compositing mixins into one big mixin?
19:46
Always favor composition over inheritance but I have seen use cases where mixins were actually extended. So if you look into the source code of Django braces, they have one kind of base.
20:01
So they have a base mixin for their access mixins that is doing some of the basic stuff and then all the others they inherit. So you can do that. That's pretty valid but just be careful. Combining them via composition, I'm not sure how would you do that.
20:23
So can't really give you an advice. More questions? Everyone's hungry. Well I don't know if they start serving food now so we might have to wait a minute anyway.
20:45
Hi, thank you for the talk at first. I was before in the decorator lectures and they were talking about how to use decorator, how many you can use. And you can use also decorator for classes. I guess it's a bit different from mixin because it's modifying the class attribute.
21:03
But the speaker also was talking about metaclasses and I was thinking how is the relation between metaclasses and mixin and what is good to use mixin for and what would you use metaclasses for if you have to use it. I haven't used metaclasses for creating mixins.
21:25
So I can't really, so can I echo your question? How would you use metaclasses if you're creating mixins or was? Just having, instead of using mixin
21:46
for adding a small methods or functionality to a class like using, having metaclasses and redefine all those, and define all those classes already with global or more broad numbers of methods
22:01
for views or something. Maybe I'm completely wrong in this question, I don't know. Yeah, I don't know much about metaclasses. So that might be also a problem. Yeah, so I definitely should take a look at this talk and learn actually about metaclasses. But I'm not sure that in metaclasses
22:21
you can do the same stuff. So yeah, definitely you can have some of your functionality separated into metaclasses. That's what basically Django is doing. So we have metaclasses for a set of functionality and then we have extra placed into mixins. But I gotta try. Maybe I can put all this code into metaclasses
22:42
and it will work. No, no, no, okay, no. Just no. Thanks for the talk. Are mixins also used in, are also popular in other contexts than Django?
23:06
If you have any of the additional models which are outside of the Django core components, so if you're doing models, you don't have mixins, obviously. So we have the template layer,
23:21
the view layer, and the model layer. So the view layer is the only place where I could see mixins, but then you can have extra logic, extra modules, where you can use mixins for your ordinary Python structure. I can't give an exact use case,
23:40
but you might have the need to use mixins, but that's going to be already outside of Django. Thanks. I can actually add something on this one. If you do forms, it's quite common to add a mixin to do like date pickers or these weird things.
24:04
Good point. Thank you. More questions? Right, so maybe we can go to lunch and please thank you Anna again. It was very good. Thank you.