But a few changes are needed: • Access your web app at: http://dev.hatcherydevshop.com/ USERNAME/ • When logging in via ssh, the above URL will be shown as a reminder • runserver works the same way, but isn’t accessible via the older http:// HOST:PORT URL • Your web app runs in a sub-path of the site, but your web app doesn’t see that! • All of this is handled by nginx 3
a template: • Provide the <form> tag • Include CSRF protection • Include any submit or cancel buttons • Django provides built-in generic form rendering 4 <form class="form-horizontal" action="" method="post"> {% csrf_token %} <button type="submit">Send Message</button> {{ form.as_p }} {{ form.as_table }} {{ form.as_ul }}
as well (useful for when a CSS template framework is used, like Bootstrap • Use an include to create a custom, reusable form rendering template • Ensure all form parts are rendered: • CSRF (but be careful if multiple Django forms are rendered in one HTML form) • Hidden fields • Form errors (non_field_errors) • Iterate over each field and render: • Label • Whether the field is required or not • Field • Field errors 5
way to represent the current location in a web app by highlighting the user’s location in the navigation bar • li items in the navbar can be highlighted using the “active” css class • To enable this functionality, navbar li elements must determine if they are “active” based on the current path • Create template tag that returns the text “active” and include this template tag in the li class for each navbar item in base.html • active template tag is a custom template tag in softball_tags.py • Takes request, to be able to example current path and a search string indicating which path is represented by the navbar item {% load softball_tags %} <li class="{% active request '/team/' %}"> <a href="{% url team_list %}">Teams</a></li> <li class="{% active request '/player/' %}"> <a href="{% url player_list %}">Players</a></li> <li class="{% active request '/game/' %}"> <a href="{% url game_list %}">Games</a></li>
lives in softball/templatetags/softball_tags.py • Method takes request and search pattern, then uses pattern as regular expression to search request.path, returning the text “active” • Custom template tags are discovered automatically by Django • Make sure that 'django.core.context_processors.request' is included in TEMPLATE_CONTEXT_PROCESSORS in settings.py import re from django import template register = template.Library() @register.simple_tag def active(request, pattern): if re.search(pattern, request.path): return 'active' return ''
in Paginator module to support paging long lists • Works by wrapping a list query in a Paginator object and using a page URL argument to indicate the current page • Ensure Paginator exceptions are caught and handled appropriately 9 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger def team_list(request): paginator = Paginator( models.Team.objects.all().order_by('name'), 10) page = request.GET.get('page') try: teams = paginator.page(page) except PageNotAnInteger: teams = paginator.page(1) except EmptyPage: teams = paginator.page(paginator.num_pages) return TemplateResponse(request, 'softball/team/list.html', { 'teams': teams, })
Forms • Enable the creation of forms that allow user manipulation of Model-based data • Inherit from ModelForm class • Specify model in Meta • Meta is similar to Model’s Meta class that customizes ModelForm instance • Fields are automatically created based on the Model’s fields • ForeignKeys are represented by ModelChoiceField, which is a type of ChoiceField • ManyToManyFields are represented by MultipleModelChoiceField, which is a type of MultipleChoiceField • In both cases, choices are generated by a queryset of related Models 11
required is set automatically based on ModelField’s blank setting • label is set automatically based on ModelField’s verbose setting • choices are set automatically based on ModelField’s choices setting • is_valid() works just like in a regular Form, but also performs Model validation • When instantiating a ModelForm, include an instance if it exists to update that instance with form data • If not specified, a new Model instance is created automatically • save() is a special ModelForm method that will create or update a Model instance based on request.POST data • If commit is not specified, save() will also create/update the instance in the database • If commit=False is specified, Model instance is created or updated, but not saved to database and must be save()’d explicitly 12
Model Fields in a ModelForm, specify either fields or exclude collections in Meta; order matters! • Override field widgets using widgets dict 14 class PartialAuthorForm(ModelForm): class Meta: model = Author fields = ('name', 'title') class PartialAuthorForm(ModelForm): class Meta: model = Author exclude = ('birth_date',) from django.forms import ModelForm, Textarea class AuthorForm(ModelForm): class Meta: model = Author fields = ('name', 'title', 'birth_date') widgets = { 'name': Textarea(attrs={'cols': 80, 'rows': 20}), }
• Must have “create” and “update” views • Create view should assume no existing instance is specified and should render an empty ModelForm • Upon successful creation, redirect to the instance view 15 def team_create(request): if request.method == 'POST': team_form = forms.TeamForm(request.POST) if team_form.is_valid(): team = team_form.save() return redirect('team_view', team_id=team.id) else: team_form = forms.TeamForm() return TemplateResponse(request, 'softball/team/create.html', { 'team_form': team_form, })
existing instance specified (or raise an Http404 exception) and should include the specified instance in the ModelForm • Pass the instance into the form for rendering (not necessary, but easy) 16 def team_edit(request, team_id=None): try: team = models.Team.objects.get(pk=team_id) except models.Team.DoesNotExist: raise Http404 if request.method == 'POST': team_form = forms.TeamForm(request.POST, instance=team) if team_form.is_valid(): team = team_form.save() return redirect('team_view', team_id=team.id) else: team_form = forms.TeamForm(instance=team) return TemplateResponse(request, 'softball/team/edit.html', { 'team': team, 'record': team.record(), 'team_form': team_form, })