@@ -936,7 +936,7 @@ class TemplateView(View):
936936
937937def render_body (self ) ->str :
938938""" Render the message body as HTML"""
939- with open (" index.html " )as fd:
939+ with open (self .template_file )as fd:
940940return fd.read()
941941
942942
@@ -947,6 +947,100 @@ source of the body, but this method has a single, well defined responsibility
947947that** invites subtypes to override it** . It is designed to be extended by its
948948subtypes.
949949
950+ Another good way to use the strengths of both object inheritance and object
951+ composition is to use[ Mixins] ( https://docs.djangoproject.com/en/4.1/topics/class-based-views/mixins/ ) .
952+
953+ Mixins are bare-bones classes that are meant to be used exclusively with other
954+ related classes. They are "mixed-in" with the target class using multiple
955+ inheritance, in order to change the target's behaviour.
956+
957+ A few rules:
958+ - Mixins should always inherit from` object `
959+ - Mixins always come before the target class, e.g.` class Foo(MixinA, MixinB, TargetClass): ... `
960+
961+ ** Also good**
962+ ``` python
963+ from dataclassesimport dataclass, field
964+ from typingimport Protocol
965+
966+
967+ @dataclass
968+ class Response :
969+ """ An HTTP response"""
970+
971+ status:int
972+ content_type:str
973+ body:str
974+ headers:dict = field(default_factory = dict )
975+
976+
977+ class View :
978+ """ A simple view that returns plain text responses"""
979+
980+ content_type= " text/plain"
981+
982+ def render_body (self ) ->str :
983+ """ Render the message body of the response"""
984+ return " Welcome to my web site"
985+
986+ def get (self ,request ) -> Response:
987+ """ Handle a GET request and return a message in the response"""
988+ return Response(
989+ status = 200 ,
990+ content_type = self .content_type,
991+ body = self .render_body()
992+ )
993+
994+
995+ class TemplateRenderMixin :
996+ """ A mixin class for views that render HTML documents using a template file
997+
998+ Not to be used by itself!
999+ """
1000+ template_file:str = " "
1001+
1002+ def render_body (self ) ->str :
1003+ """ Render the message body as HTML"""
1004+ if not self .template_file:
1005+ raise ValueError (" The path to a template file must be given." )
1006+
1007+ with open (self .template_file)as fd:
1008+ return fd.read()
1009+
1010+
1011+ class ContentLengthMixin :
1012+ """ A mixin class for views that injects a Content-Length header in the
1013+ response
1014+
1015+ Not to be used by itself!
1016+ """
1017+
1018+ def get (self ,request ) -> Response:
1019+ """ Introspect and amend the response to inject the new header"""
1020+ response= super ().get(request)#type: ignore
1021+ response.headers[' Content-Length' ]= len (response.body)
1022+ return response
1023+
1024+
1025+ class TemplateView (TemplateRenderMixin ,ContentLengthMixin ,View ):
1026+ """ A view that returns HTML responses based on a template file."""
1027+
1028+ content_type= " text/html"
1029+ template_file= " index.html"
1030+
1031+ ```
1032+
1033+ As you can see, Mixins make object composition easier by packaging together
1034+ related functionality into a highly reusable class with a single responsibility,
1035+ allowing clean decoupling. Class extension is achieved by "mixing-in" the
1036+ additional classes.
1037+
1038+ The popular Django project makes heavy use of Mixins to compose its class-based
1039+ views.
1040+
1041+ FIXME: re-enable typechecking for the line above once it's clear how to use
1042+ ` typing.Protocol ` to make the type checker work with Mixins.
1043+
9501044###** Liskov Substitution Principle (LSP)**
9511045###** Interface Segregation Principle (ISP)**
9521046###** Dependency Inversion Principle (DIP)**