Pro Yearly is on sale from $80 to $50! »

Django Views: Functions, Classes, and Generics

767450215aa2f669a3dcaefa5beb4643?s=47 Andrew Pinkham
September 07, 2015

Django Views: Functions, Classes, and Generics

Presented at DjangoCon US 2015.

At the heart of Django is the HTTP Request and Response cycle, powered by URL patterns and views that you must create. But what kind of view should you use? A view function? A class-based view? A generic class-based view? This talk is all about the essence of views, and will explore the differences, advantages and disadvantages of each type of view, finishing with a guide of when to use what.

http://andrewsforge.com/presentation/django-views-functions-classes-generics/

767450215aa2f669a3dcaefa5beb4643?s=128

Andrew Pinkham

September 07, 2015
Tweet

Transcript

  1. ANDREW PINKHAM TOPIC DATE AUTHOR SEPTEMBER 2015 VIEWS: FUNCTIONS, CLASSES

    & GENERICS DJANGOCON US 2015
  2. $ whoami Software Engineer Freelance Consultant Technical Instructor Andrew Pinkham

    Hi, I’m
  3. AUTHOR OF DJANGO UNLEASHED AVAILABLE FOR PREORDER; SHIPS DECEMBER 2015

  4. Answers today: Django handles HTTP for me! Why do I

    have to worry about it? When is Django deprecating function views? Aren’t all class-based views generic? How do I choose what kind of view to use?
  5. $ ls views 1_fundamentals 2_views 3_tools

  6. $ ls views 1_fundamentals -> problem, meet solution 2_views ->

    examining the solution 3_tools -> making the solution easier
  7. $ less views/1_fundamentals What is a callable? What is HTTP,

    anyway? Django's HTTP request/response cycle A view’s purpose
  8. $ less views/2_views A Brief History of Views Functions Views

    Class Based Views Generic Class Based Views
  9. $ less views/3_tools Enhance! When to Use What

  10. afrg.co/views

  11. PYTHON CALLABLES UNDERSTANDING THE PROBLEM

  12. def a_function(*args, **kwargs): return 'Hello DjangoCon 2015!' >>> a_function() 'Hello

    DjangoCon 2015!'
  13. >>> lambda_function = lambda: 'Enjoying Austin?' >>> lambda_function() 'Enjoying Austin?'

  14. class FirstClass: an_attribute = ( 'Have you visited any good

    restaurants?') def a_method(*args, **kwargs): self = args[0] return self.an_attribute >>> fc_obj = FirstClass() >>> fc_obj.a_method() 'Have you visited any good restaurants?'
  15. class SecondClass(FirstClass): def __init__(self): """Magic method to initialize a class"""

    self.an_attribute = ( "Easy Tiger, La Condessa and " "Lambert's are my favorites.") >>> sc_obj = SecondClass() >>> sc_obj.a_method() "Easy Tiger, La Condessa and Lambert's are my favorites."
  16. class ThirdClass(SecondClass): def __call__(*args, **kwargs): """Magic method to make object

    callable""" return ( "I like grabbing ice cream at " "Amy's, too.") >>> tc_obj = ThirdClass() >>> tc_obj() "I like grabbing ice cream at Amy's, too."
  17. >>> callable(a_function) True >>> callable(lambda_function) True >>> callable(FirstClass) True >>>

    callable(fc_obj) False >>> callable(sc_obj) False >>> callable(tc_obj) True
  18. WHAT IS HTTP, ANYWAY? UNDERSTANDING THE PROBLEM

  19. HyperText Transfer Protocol Defines a client and server how to

    communicate HTTP Request Methods HTTP Response Codes Safe Methods and Idempotent Methods
  20. HyperText Transfer Protocol Methods GET HEAD OPTIONS POST PUT Codes

    200 400 403 404 500
  21. HyperText Transfer Protocol Idempotent Methods POST PUT

  22. None
  23. Your website must adhere to HTTP

  24. Andrew’s Server Request Methods GIMME HAVE Response Code CANHAS NOPE

  25. Your website must adhere to HTTP

  26. Goal of Software Solve a Problem Automate Behavior

  27. None
  28. Goal of Software Solve a Problem Automate Behavior

  29. HTTP is the problem web frameworks solve You are the

    behavior frameworks automate
  30. DJANGO’S REQUEST/RESPONSE CYCLE UNDERSTANDING THE PROBLEM

  31. What is a view? 'A view is a "type" of

    Web page' "views are for displaying content" (DORK-1) Dynamic generation of content
  32. Step 3. HTTP Response Step 1. HTTP Request Website Step

    2. Computation
  33. Database Views URL Dispatch URL Patterns Template Loader Template Files

    Models Forms Context Processors
  34. Simplification No WSGI Server No View Middleware No Exception Handling

  35. Views URL Dispatch URL Patterns

  36. Views URL Patterns METHOD /path/to/resource/ HTTP/1.1

  37. Views URL Patterns METHOD /path/to/resource/ HTTP/1.1 METHOD /path/to/resource/ HTTP/1.1

  38. Views URL Patterns METHOD /path/to/resource/ HTTP/1.1 METHOD /path/to/resource/ HTTP/1.1

  39. What is a view? Accept HttpRequest object Generate data based

    on: HTTP request method Request data (POST, PUT, etc) Data from dispatch (from the URL path) Return HttpResponse object
  40. What is a view? Any Python Callable

  41. Why do we talk about functions and classes (and generics)?

  42. A BRIEF HISTORY OF VIEWS FROM WHEN DINOSAURS STILL ROAMED

    THE EARTH UNTIL THE ROBOT APOCALYPSE
  43. A Brief History of Views July 2005: Django Function views

    in original tarball July 2005: Generic views in SVN revision 304
  44. Functions are Rigid Extend generic views? Use classes!

  45. The big win from a class-based view is [...] being

    able to override parts of the behavior without needing to rewrite the entire view, or add 101 parameters. –Alex Gaynor https://groups.google.com/d/msg/django-developers/J87Hm3hO9z8/gWunEs9QwMwJ
  46. A Brief History of Views July 2005: Django Function views

    in original tarball July 2005: Generic views in SVN revision 304 March 2008: Joseph Kocherhans #6735
  47. Class-Based Views Simple (Usable - principle of least surprise) Extendable

    Inheritance Decorators Safe (Thread-Safe) Testable
  48. A Brief History of Views July 2005: Django Function views

    in original tarball July 2005: Generic views in SVN revision 304 March 2008: Joseph Kocherhans #6735 March 2011: (G)CBV Released in Django 1.3
  49. The Naming Problem Generic Views Class-Based Views (CBV) Class-Based +

    Generic Views (CBGV)
  50. The Naming Problem Object Views Generic (Class-Based) Views (GCBV)

  51. State of the Pony Function Views Object Views (Class-Based Views)

    Generic (Class-Based) Views
  52. FUNCTION VIEWS HOW I LEARNED TO STOP WORRYING AND LOVE

    NON-COMPLIANCE
  53. class ExampleModel(models.Model): name = models.CharField(max_length=31) slug = models.SlugField(max_length=31) def __str__(self):

    return self.name.title()
  54. from django.conf.urls import url from . import views urlpatterns =

    [ url(r'^(?P<slug>[\w\-]+)/$', views.model_detail, name='model_detail'), ]
  55. from django.shortcuts import ( get_object_or_404, render) from .models import ExampleModel

    def model_detail(request, *args, **kwargs): request_slug = kwargs.get('slug') example_obj = get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  56. Database Views URL Dispatch URL Patterns Template Loader Template Files

    Models Forms Context Processors
  57. from django.shortcuts import ( get_object_or_404, render) from .models import ExampleModel

    def model_detail(request, *args, **kwargs): request_slug = kwargs.get('slug') example_obj = get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  58. Views URL Patterns METHOD /path/to/resource/ HTTP/1.1 METHOD /path/to/resource/ HTTP/1.1

  59. from django.http import HttpResponseNotAllowed def model_detail(request, *args, **kwargs): if request.method

    == 'GET': request_slug = kwargs.get('slug') example_obj = get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj}) return HttpResponseNotAllowed(['GET'])
  60. from django.views.decorators.http import \ require_http_methods @require_http_methods(['GET', 'HEAD']) def model_detail(request, *args,

    **kwargs): request_slug = kwargs.get('slug') example_obj = get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  61. @require_http_methods(['GET', 'HEAD']) def model_detail(request, *args, **kwargs): ... ‑ @require_safe def

    model_detail(request, *args, **kwargs): ...
  62. $ ./manage.py runserver $ telnet localhost 8000

  63. GET /django/ HTTP/1.1 HTTP/1.0 200 OK Date: Wed, 26 Aug

    2015 17:38:38 GMT Server: WSGIServer/0.2 CPython/3.4.3 Content-Type: text/html; charset=utf-8 X-Frame-Options: SAMEORIGIN
  64. OPTIONS /django/ HTTP/1.1 HTTP/1.0 405 METHOD NOT ALLOWED Date: Wed,

    26 Aug 2015 17:43:44 GMT Server: WSGIServer/0.2 CPython/3.4.3 Allow: GET, HEAD Content-Type: text/html; charset=utf-8 X-Frame-Options: SAMEORIGIN
  65. POST /django/ HTTP/1.1 HTTP/1.0 403 FORBIDDEN Date: Wed, 26 Aug

    2015 17:41:45 GMT Server: WSGIServer/0.2 CPython/3.4.3 Content-Type: text/html X-Frame-Options: SAMEORIGIN
  66. url(r'^create/$', views.model_create, name='model_create'),

  67. def model_create(request, *args, **kwargs): if request.method == 'POST': form =

    ExampleForm(request.POST) if form.is_valid(): new_obj = form.save() return redirect(new_obj) else: form = ExampleForm() return render( request, 'viewsapp/form.html', {'form': form})
  68. None
  69. @require_http_methods(['GET', 'HEAD', 'POST']) def model_create(request, *args, **kwargs): ...

  70. CLASS-BASED VIEWS AS DRY AS THE SAHARA

  71. url(r'^(?P<slug>[\w\-]+)/$', views.ModelDetail.as_view(), name='model_detail'),

  72. @require_safe def model_detail(request, *args, **kwargs): request_slug = kwargs.get('slug') example_obj =

    get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  73. def model_detail(request, *args, **kwargs): request_slug = kwargs.get('slug') example_obj = get_object_or_404(

    ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  74. def get(self, request, *args, **kwargs): request_slug = kwargs.get('slug') example_obj =

    get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  75. class ModelDetail(View): def get(self, request, *args, **kwargs): request_slug = kwargs.get('slug')

    example_obj = get_object_or_404( ExampleModel, slug=request_slug) return render( request, 'viewsapp/detail.html', {'object': example_obj})
  76. OPTIONS /django/ HTTP/1.1 HTTP/1.0 200 OK Date: Wed, 26 Aug

    2015 17:48:24 GMT Server: WSGIServer/0.2 CPython/3.4.3 Allow: GET, HEAD, OPTIONS X-Frame-Options: SAMEORIGIN Content-Type: text/html; charset=utf-8 Content-Length: 0
  77. url(r'^create/$', views.ModelCreate.as_view(), name='model_create'),

  78. class ModelCreate(View): context_object_name = 'form' form_class = ExampleForm template_name =

    'viewsapp/form.html' def get(self, request, *args, **kwargs): ... def post(self, request, *args, **kwargs): ...
  79. class ModelCreate(View): def get(self, request, *args, **kwargs): return render( request,

    self.template_name, {self.context_object_name: self.form_class()})
  80. class ModelCreate(View): def post(self, request, *args, **kwargs): bound_form = self.form_class(request.POST)

    if bound_form.is_valid(): new_obj = bound_form.save() return redirect(new_obj) return render( request, self.template_name, {self.context_object_name: bound_form})
  81. @require_http_methods(['GET', 'HEAD', 'POST']) def model_create(request, *args, **kwargs): if request.method ==

    'POST': form = ExampleForm(request.POST) if form.is_valid(): new_obj = form.save() return redirect(new_obj) else: form = ExampleForm() return render( request, 'viewsapp/form.html', {'form': form})
  82. class ModelCreate(View): def get(self, request, *args, **kwargs): # show form

    def post(self, request, *args, **kwargs): # show form if error # use data if valid
  83. GENERIC CLASS-BASED VIEWS OH FOR THE LOVE OF GRAPH THEORY

  84. from django.views.generic import DetailView, View class ModelDetail(DetailView): model = ExampleModel

    template_name = 'viewsapp/detail.html'
  85. from django.views.generic import ( CreateView, DetailView) class ModelCreate(CreateView): context_object_name =

    'form' form_class = ExampleForm template_name = 'viewsapp/form.html'
  86. The Problem put(*args, **kwargs) The PUT action is also handled

    and just passes all parameters through to post(). https://docs.djangoproject.com/en/1.8/ref/class-based-views/mixins-editing/ #django.views.generic.edit.ProcessFormView.put
  87. None
  88. None
  89. None
  90. None
  91. None
  92. https://ccbv.co.uk

  93. Stick to the basics display a list of objects display

    a single object create a single object update a single object delete a single object
  94. None
  95. ENHANCE! MAKING VIEWS EASIER

  96. Classy Class Based Views http://ccbv.co.uk

  97. None
  98. None
  99. None
  100. None
  101. None
  102. django-decorator-plus

  103. from decorator_plus import ( require_form_methods, require_safe_methods) @require_safe_methods def model_detail(request, *args,

    **kwargs): ... @require_form_methods def model_create(request, *args, **kwargs): ...
  104. from decorator_plus import require_http_methods @require_http_methods(['GET']) def model_detail(request, *args, **kwargs): ...

    @require_http_methods(['GET', 'POST']) def model_create(request, *args, **kwargs): ...
  105. @require_safe_methods @require_http_methods(['GET']) @require_form_methods @require_http_methods(['GET', 'POST']) HEAD && OPTIONS Included

  106. IN CONCLUSION ONE SIZE FITS NO-ONE

  107. Answers: Django handles HTTP for me! Why do I have

    to worry about it? When is Django deprecating function views? Aren’t all class-based views generic? How do I choose what kind of view to use?
  108. The Questions Does a generic view do what I want

    (or almost)? If so, use a generic (and https://ccbv.co.uk). Do I need to inherit/share behavior with another view? If so, use a CBV. If not, then it doesn’t matter.
  109. Key Take-Aways The view is Django’s solution to HTTP methods

    All views are callables require_http_methods() should be used with function views Generic Class-Based Views (GCBV) are pre- programmed Class-Based Views (CBV), and are separate concepts with different uses
  110. Thank you! Related Materials: afrg.co/views Django Unleashed: afrg.com/dju Django Class:

    afrg.co/class @andrewsforge