Two scoops of django 1.6 - Ch7, Ch8

20
Two Scoops of Django Ch 7. Function-and Class-Based Views Ch 8. Best Practices for Function-Based Views 2014/11/04 Michelle Leu @flywindy

description

Ch 7. Function-and Class-Based Views Ch 8. Best Practices for Function-Based Views

Transcript of Two scoops of django 1.6 - Ch7, Ch8

Page 1: Two scoops of django 1.6  - Ch7, Ch8

Two Scoops of DjangoCh 7. Function-and Class-Based Views

Ch 8. Best Practices for Function-Based Views

2014/11/04Michelle Leu @flywindy

Page 2: Two scoops of django 1.6  - Ch7, Ch8

Agenda

Django Views

FBVs v.s. CBVs

Best practices for FBVs

URL Namespaces

Loose Coupling

Summary

Page 3: Two scoops of django 1.6  - Ch7, Ch8

Django Views

y = f(x) # math

HttpResponse = view(HttpRequest) # FBV

HttpResponse = View.as_view(HttpRequest) # CBV

Django Views are functions

Page 4: Two scoops of django 1.6  - Ch7, Ch8

Django Views

keep business logic out of Views

model methods

manger methods

general utility helper function

forms

Business logic is the part of the program

that encodes the real-world business rules that determine how data can be created,

displayed, stored, and changed…….

(From wikipedia)

Page 5: Two scoops of django 1.6  - Ch7, Ch8

FBVs (Function Based Views)

Django 1.7 Tutorial Part 3 # polls/views.py…from django.shortcuts import renderfrom polls.models import Question

def index(request): latest_question_list = Question.objects.all().order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context)

def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question})

def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question})

Page 6: Two scoops of django 1.6  - Ch7, Ch8

CBVs (Class Based Views)

Django 1.7 Tutorial Part 4

# polls/views.py…from django.views import genericfrom polls.models import Question

class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list'

def get_queryset(self): """Return the last five published questions.""" return Question.objects.order_by('-pub_date')[:5]

class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html'

class ResultsView(generic.DetailView): model = Question template_name = 'polls/results.html'

Page 7: Two scoops of django 1.6  - Ch7, Ch8

CBVs v.s. FBVs

Page 8: Two scoops of django 1.6  - Ch7, Ch8

CBVs v.s. FBVs

For new comer: FBVs

For new project: CBVs

For past project: FBVs for most views, CBVs only for views that need to be subclassed.

Write custom 403, 404, and 500 error handlers: FBVs # root URLconf

handler500 = 'mysite.views.my_custom_error_view'

Page 9: Two scoops of django 1.6  - Ch7, Ch8

Best practices for FBVs

Pass HttpRequest Object

Pass HttpResponse Object

Decorators

Page 10: Two scoops of django 1.6  - Ch7, Ch8

Decorators

simple decorator template

# EXAMPLE 8.5import functools

def decorator(view_func):

@functools.wraps(view_func) def new_view_func(request, *args, **kwargs): # modify HttpRequest object here response = view_func(request, *args, **kwargs) # modify HttpResponse object here return response

return new_view_func

Page 11: Two scoops of django 1.6  - Ch7, Ch8

Decorators

# EXAMPLE 8.6# sprinkles/decorators.pyfrom functools import wrapsfrom . import utils

def check_sprinkles(view_func): @wraps(view_func) def new_view_func(request, *args, **kwargs): # modify HttpRequest object here request = utils.can_sprinkle(request) # request.can_sprinkle response = view_func(request, *args, **kwargs) # modify HttpResponse object here return response return new_view_func

# EXAMPLE 8.7# sprinkles/views.py...from .decorators import /check_sprinkles

@check_sprinklesdef sprinkle_detail(request, pk): sprinkle = get_object_or_404(Sprinkle, pk=pk)

return render(request, "sprinkles/sprinkle_detail.html", {"sprinkle": sprinkle})

Page 12: Two scoops of django 1.6  - Ch7, Ch8

URL Namespacesallow you to uniquely reverse named URL patterns even if different applications use the same URL names.

are specified using the ':' operator. For example, the main index page of the admin application is referenced using 'admin:index'. This indicates a namespace of 'admin', and a named URL of ‘index'.

can also be nested.

# EXAMPLE 7.3# urls.py at root of projectfrom django.conf.urls import include, url

urlpatterns += patterns('', url(r'^tastings/', include('tastings.urls', namespace='tastings')),)

Page 13: Two scoops of django 1.6  - Ch7, Ch8

URL Namespacesallow you to uniquely reverse named URL patterns even if different applications use the same URL names.

are specified using the ':' operator. For example, the main index page of the admin application is referenced using 'admin:index'. This indicates a namespace of 'admin', and a named URL of ‘index'.

can also be nested.

# EXAMPLE 7.3# urls.py at root of projectfrom django.conf.urls import include, url

urlpatterns += patterns('', url(r'^tastings/', include('tastings.urls', namespace='tastings')),)

# EXAMPLE 7.4# tastings/views.py snippet……class TasteUpdateView(UpdateView): model = Tasting def get_success_url(self): return reverse("tastings:detail", kwargs={"pk": self.object.pk})

Page 14: Two scoops of django 1.6  - Ch7, Ch8

URL Namespaces

# EXAMPLE 7.5# tastings/detail.html snippet……<ul> {% for tasting in tastings %} <li> <a href="{% url "tastings:detail" tasting.pk %}">{{ tasting.title }}</a> <small> (<a href="{% url "tastings:update" tasting.pk %}">update</a>) </small> </li> {% endfor %}<ul>……

Page 15: Two scoops of django 1.6  - Ch7, Ch8

Why URL Namespaces?

Makes for shorter, more obvious and DRY URL names

Increases interoperability with Third-party libraries

Easier searches, upgrades, and refactors

Allow for more app and template reverse tricks

Page 16: Two scoops of django 1.6  - Ch7, Ch8

Loose Coupling

鬆散耦合

相對於 緊密耦合(tight coupling)

In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components ….… (From wikipedia)

Page 17: Two scoops of django 1.6  - Ch7, Ch8

Loose Coupling# BAD EXAMPLE 7.1

from django.conf.urls import patterns, urlfrom django.views.generic import /DetailView

from tastings.models import Tasting

urlpatterns = patterns('', url(r'^(?P<pk>\d+)/$', DetailView.as_view( model=Tasting, template_name='tastings/detail.html'), name='detail'), url(r'^(?P<pk>\d+)/results/$', DetailView.as_view( model=Tasting, template_name='tastings/results.html'), name='results'),)

authentication︖?

Page 18: Two scoops of django 1.6  - Ch7, Ch8

閃開,讓專業的來!

Loose Coupling

# EXAMPLE 7.1# tastings/views.py

from django.views.generic import /DetailView

from tastings.models import Tasting

class TasteDetailView(DetailView): model = Tasting

class TasteResultsView(TasteDetailView): template_name = 'tastings/results.html'

# EXAMPLE 7.1# tastings/urls.py

from django.conf.urls import patterns, url

from . import views

urlpatterns = patterns('', url(r'^(?P<pk>\d+)/$', views.TasteDetailView.as_view(), name='detail'), url(r'^(?P<pk>\d+)/results/$', views.TasteResultsView.as_view(), name='results'),)

<app_label>/<model_name><template_name_suffix>.html -> tastings/tasting_detail.html

Page 19: Two scoops of django 1.6  - Ch7, Ch8

Summary

Don’t Repeat Yourself. (DRY)

Do one thing and do it well.

Views should handle presentation logic.

Less code is better, and keep it simple.

Complex nested-if blocks are to be avoided.

Page 20: Two scoops of django 1.6  - Ch7, Ch8

References

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

Django project 1.7 tutorial: https://docs.djangoproject.com/en/1.7/intro/tutorial01/

Django project 1.7 - URL namespaces: https://docs.djangoproject.com/en/1.7/topics/http/urls/#url-namespaces

Django Girls 學習⼿手冊: http://djangogirlstaipei.gitbooks.io/django-girls-taipei-tutorial/

two-scoops-of-django-1.6 issues: https://github.com/twoscoops/two-scoops-of-django-1.6/issues?q=is%3Aopen+is%3Aissue