First, the form form
In order to receive the user's choice vote, we need to show poll interface in a front page
polls/detail.html
<h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> {% endfor %} <input type="submit" value="Vote"> </form>
- forloop.counter is a variable DJango template system specially provided to indicate the number of your current cycle, the cycle is generally used to add items ordered logarithmic scale.
- Since we send a POST request, we must consider the safety of a cross-site request forgery, referred to as CSRF (specific meaning please Baidu). Django provides you with a simple way to avoid this trouble, it is added in the form form a {% csrf_token%} tag, label name can not be changed, fixed format, in any position, as long as the form is in the form. This method is convenient Haoshi submission form on the form of the way, but if it is submitting data using ajax way, then do not use this method has.
vote view function (polls / views.py) process
def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
request.POST is a dictionary-like object, allowing you to submit data access by key name. In this example, request.POST[’choice’]
it returns the ID of the selected option, and a type value of a string is always a string, even if it looks like a digital!
request.POST[’choice’]
There may trigger a KeyError exception if your choice is not provided in POST data key, in this case, the above code will return the form page and gives an error message. PS: Usually we give a default value, to prevent such an exception, for example request.POST[’choice’,None]
,
After selecting the counter plus one, is a return HttpResponseRedirect
instead we used previously HttpResponse
. HttpResponseRedirect takes one parameter: the redirected URL. Here's a suggestion, when you successfully handle POST data, should maintain a good habit, always returns a HttpResponseRedirect. This is not just for Django, it's a good habit to develop WEB.
We used one above HttpResponseRedirect the constructor reverse()
function. It can help us to avoid hard-coded URL in the view function. It first requires a URLconf we specified in the name, and then the data transfer. For example '/polls/3/results/'
, where 3 is a question.id
value. After entering the redirection polls:results
corresponding view, and question.id
is passed to it.
When someone vote on an issue, vote () view redirects to the questionnaire results display page. Let's write this view processing results pages (polls / views.py):
from django.shortcuts import get_object_or_404, render def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question})
templatepolls/templates/polls/results.html
<h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">Vote again?</a>
Second, the use of generic views: reducing code duplication
Improved URLconf
Open the polls/urls.py
file, edit it into something like the following:
rom django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]
Modify View
Next, open polls/views.py
a file, delete the index, detail view of the results and, to replace the general view of Django
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' def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST.get('choice')) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', { 'question': question, 'error_message': "You didn't select a choice.", }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
We used two common view ListView
and DetailView
(they are inherited as a parent). Both represent "displays a list of objects" and "Display detail page of a particular type of object" abstraction.
-
Each generic view needs to know what it is to act on the model, this model provided by the property.
-
DetailView
Need to capture the url to the primary key called "pk", so we in the url file 2 and 3 entries<question_id>
modified into<pk>
.
By default, the DetailView
general view is referred to using a <app name>/<model name>_detail.html
template. In the present example, it is actually used polls/detail.html
. template_name
This attribute is used to specify the name of the template, the template used in place of the default name is automatically generated. (Be sure to carefully observe the code above, condemnation, attention to detail) Similarly, in resutls list view, designated template_name
as 'polls/results.html'
, thus ensuring although resulst view and the detail view also inherited DetailView class, using the same model: Qeustion but they will still show different pages. (Templates for different Well! So easy!)
Similar, ListView generic view uses a template called default <app name>/<model name>_list.html
. We also use template_name
this variable to tell ListView to use our existing "polls/index.html"
template, rather than using its own default one.
In the front part of the tutorial, we provide a template to contain question
and latest_question_list
context variables. For DetailView, question'll be automatically provided, because we use Django's model (Question), Django will intelligently select the appropriate context variables. However, for the ListView, automatic generation of context variables question_list
. To cover it, we offer a context_object_name
property that specifies that we want to use latest_question_list
instead question_list
.
Third, static files
In addition to HTML files generated by the server, WEB applications typically need to provide some other necessary documents, such as image files, JavaScript scripts and CSS style sheets, and so on, the user is presented to a full page. In Django, we refer to these documents collectively referred to as "static files", because the contents of these documents is basically fixed, you do not need to dynamically generated.
For small projects, these are not a big problem, you can still file anywhere in your web server can be found. But for large projects, especially those that contain multiple app project, including the treatment of those different sets of static files from the app brings a hassle alive.
But this is the django.contrib.staticfiles
purpose: It collects each application (and any place you specify) static files to a place designated unified, and easy to access.
Create a directory in the polls static
directory. Django looks for static files in there, which is looking for ways to Django corresponding template file is the same in polls / templates / in.
Django's STATICFILES_FINDERS
setting items included in a search list, they know how to find static files from a variety of sources. One of the default Finder Shi AppDirectoriesFinder
,
It is for each INSTALLED_APPS
to find the next static
subdirectory, such as the one we just created static
directory. admin management site also uses the same directory structure for its static files.
static
Create a new directory in polls
a subdirectory, and then create a subdirectory in the style.css
file
Good directory structure is that each application should create their own urls, forms, views, models, templates and static, each of the templates contains a subdirectory with the same name as the application, each static application also contains a subdirectory with the same name.
polls/static/polls/style.css
:
li a {
color: green;
}
In the template file polls/templates/polls/index.html
referenced head
{% load static %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
{% static %}
Template tags will generate an absolute URL path static files.
Restart the server, access the browser http://localhost:8000/polls/
, you'll see a hyperlink into a green Question
Add a background image
In polls/static/polls/
creating a directory for storing pictures images
subdirectory, put `background.gif file in the subdirectory
Css style file in polls/static/polls/style.css
the Add
body { background: white url("images/background.gif") no-repeat; }
Reload http://localhost:8000/polls/
(CTRL + F5 or directly F5), you will see the loaded background image in the upper left corner of the screen
prompt:
{% static %}
Template tags can not be used in static files, such as style sheets, because they are not generated by Django. You should use a relative path to link to each other static files
Direct access to static files
Reference Liu Jiang's blog tutorial