Two scoops of django 1.6 - Ch7, Ch8
description
Transcript of 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
Agenda
Django Views
FBVs v.s. CBVs
Best practices for FBVs
URL Namespaces
Loose Coupling
Summary
Django Views
y = f(x) # math
HttpResponse = view(HttpRequest) # FBV
HttpResponse = View.as_view(HttpRequest) # CBV
Django Views are functions
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)
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})
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'
CBVs v.s. FBVs
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'
Best practices for FBVs
Pass HttpRequest Object
Pass HttpResponse Object
Decorators
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
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})
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')),)
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})
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>……
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
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)
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︖?
閃開,讓專業的來!
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
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.
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