Create a polling site with Django (iv)

Source: Internet
Author: User

Create your first Django project, part fourth

This article continues from the end of Part three (zh). We will continue to write voting applications, focusing on simple forms processing and streamlining our code.

Write a simple form

Let's update the template ("polls/detail.html") of the poll detail page written in the previous tutorial to include an HTML <form> element:

<!---polls/template/polls/detail.html--<h1>{{Question.question_text}}</h1>{% if error_message%}<P><strong>{{Error_message}}</Strong></p>{% endif%}<Formaction="{% url ' polls:vote ' question.id%}"Method="POST" >{% Csrf_token%}{% for choice in question.choice_set.all%}<InputType= "Radio" name= "choice" id= "choice{{Forloop.counter}}" value=< Span class= "Hljs-value" > "{{choice.id}}"/> <label for= "choice{{Forloop.counter}}" >{{Choice.choice_text}}</label><br/> {% ENDFOR%} <input type=  "submit" value= "Vote"/></FORM>        

Brief description:

    • The above template adds a radio button before each Choice in the Question. The value property of each radio button is the corresponding ID of each Choice. The name of each radio button is "Choice". This means that when someone chooses a radio button and submits a form submission, it sends a POST data choice=#, where # is the ID of the selected choice. This is the basic concept of HTML forms.
    • We set the action of the form to {% url ' polls:vote ' question.id%}and set the method= "POST". It is important to use method= "POST"(as opposed to method= "get") because the behavior of this commit form alters the server-side data. Whenever you need to create a form that alters server-side data, use method= "POST". This is not a specific Django technique; it's a good website development practice.
    • forloop.counter indicates how many times the for label has been cycled.
    • Since we create a POST form (which has the effect of modifying data), we need to be careful about cross-site request forgery. Thankfully, you don't have to worry too much, because Django already has a very easy-to-use system to defend against it. In short, all POST forms for internal URLs should use the {%csrf_token%} template label.

Now, let's create a Django view to process the submitted data. Remember, in the third part of the tutorial (zh), we created a URLconf for the voting app, including this line:

# polls/urls.pyurl(r‘^(?P<question_id>[0-9]+)/vote/$‘, views.vote, name=‘vote‘),

We also created a virtual implementation of the vote () function. Let's create a real version. Add the following code to the polls/views.py:

# polls/views.pyFrom Django.shortcutsImport get_object_or_404, RenderFrom Django.httpImport Httpresponseredirect, HttpResponseFrom Django.core.urlresolversImport ReverseFrom. ModelsImport Choice, Question# ...DefVotetry:selected_choice = P.choice_set.get (pk=request. Post[ ' Choice ']) except (Keyerror, choice.doesnotexist): # to re-display the question poll form return render (Request,  Polls/detail.html ', { ' question ': P,  ' error_message ':  "You didn ' t select a choice.",}) else:selected_choice.votes + = 1 selected_choice.save () # after successfully processing post data, always return a Httpresponseredirect. Prevents the user from being submitted two times because they clicked the back button. return httpresponseredirect (reverse ( ' Polls:results ', args= ( P.id,))               

Some of the above code has not been mentioned in this tutorial:

  • request. POST is a class Dictionary object that allows you to get the submitted data by the name of the keyword. In this example,request. post[' Choice ' returns the ID of the selected choice as a string. request. the value of the POST is always a string. Note that Django also provides the request in the same way . Get is used to access get data--but we explicitly use request in code . Post to ensure that the data can only be changed via post calls.

  • If choiceis not provided in the POST data,request. post[' Choice '] will raise a keyerror. The above code checks Keyerror, and if not given choice will re-display the question form and an error message.

  • After increasing the number of votes in the choice, the code returns a httpresponseredirect instead of the usual HttpResponse. Httpresponseredirect only receives one parameter: the URL to which the user will be redirected (keep looking, we'll explain how to construct the URL in this example). As noted in the Python note above, you should always return a httpresponseredirectafter successfully processing the post data. This is not a specific Django technique; This is the consensus that good websites have developed in the development practice.

  • In this example, we use the reverse () function in the Httpresponseredirect constructor. This function avoids the hard-coded URL in the view function. It requires that we give the name of the view that we want to jump to and the parameters that need to be provided to the view in the URL pattern for that view. In this example, using the urlconf set in the third part (ZH), the reverse () call returns a string like this:

‘/polls/3/results/‘

... Where 3 is the value of p.id . The redirected URL will call the ' results ' view to display the final page.

?

As mentioned in the third part (ZH),request is a httprequest object. For more information about HttpRequest objects, see the documentation for requests and responses .

When someone votes on Question, thevote () view redirects the request to the results interface of the Question. Let's write this view:

 # polls/views.pyfrom Django.shortcuts import get_object_or_404, Renderdef results (request, question_id): Question = get_object_or_404 (question, pk=question_id) return render (Request,  ' polls/results.html ', { ' question ': question})  From Django.http import httpresponse def index (Request): return HttpResponse (" Hello, world. You ' re at the polls Index. ")              

This is almost identical to the detail () view in the third part (ZH). The only difference is the name of the template. We will resolve this redundancy issue later.

Now, create a polls/results.html template:

 <!---polls/templates/polls/results.htm-->< Span class= "Hljs-tag" ><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>          

Now, visit /polls/1/ in your browser and vote for Question. You should see a poll results page that will be updated after each vote. If you do not select any choice when you submit, you should see the error message.

Use a common view: The code is still less good.

Detail () (in the third part (ZH)) and results () view are simple-and, as mentioned above, there is a redundancy problem. The index () view used to display a list of issues (also in the third part (ZH)) is similar to them.

These views reflect a common scenario in basic WEB development: Getting data from a database based on parameters in a URL, loading a template file, and then returning the rendered template. Because this is particularly common, Django provides a shortcut called a "common view" system.

The generic view abstracts common patterns so that you don't even have to write Python code when you write your app.

Let's convert our voting app to use a common view system so that we can delete many of our code. We just need to do the following steps to complete the conversion: we will:

    1. Convert URLconf.
    2. Remove some old code that is no longer needed.
    3. Introduce a new view based on the Django common view.

Please read on to learn more.

Why refactor code?

In general, when writing a Django application, you should first evaluate whether the generic view solves your problem, and you should use it at the beginning instead of refactoring the code in half. This tutorial has so far focused on writing a view in a "tough way" to focus on core concepts.

Just like you need to know the basic math before using the calculator.

Modified URLconf

First, open the polls/urls.py this URLconf and modify it to:

# polls/urls.pyfrom django.conf.urls import urlfrom . import viewsurlpatterns = [ url(r‘^$‘, views.IndexView.as_view(), name=‘index‘), url(r‘^(?P<pk>[0-9]+)/$‘, views.DetailView.as_view(), name=‘detail‘), url(r‘^(?P<pk>[0-9]+)/results/$‘, views.ResultsView.as_view(), name=‘results‘), url(r‘^(?P<question_id>[0-9]+)/vote/$‘, views.vote, name=‘vote‘),]

Note in the second and third pattern of regular expressions, the name of the matching pattern is changed from <question_id> to <pk>.

Improved view

Next, we'll delete the old index, detail , and results views and replace them with Django's generic view. Open the polls/views.py file and modify it to:

# polls/views.pyFrom Django.shortcutsImport get_object_or_404, RenderFrom Django.httpImport HttpresponseredirectFrom Django.core.urlresolversImport ReverseFrom Django.viewsImport genericFrom. ModelsImport Choice, QuestionClassIndexview(Generic. ListView): Template_name =' polls/index.html ' context_object_name =' Latest_question_list 'DefGet_queryset "" "returns the last 5 issues" "" return Question.objects.order_by ( '-pub_date ') [: 5] class detailview  ' polls/detail.html '  class resultsview (generic. DetailView): Model = Question Template_name =  ' polls/results.html ' def vote  (request, question_id): ... # as above save             

Here we use two common views: ListView and DetailView. The two views respectively abstract the "show a list of objects" and "show detail pages for a specific type of object".

    • Each common view needs to know which model it will work on. This is provided by the model property.
    • DetailView expects to capture the primary key value named "PK" from the URL, so we change the question_id to PK for the generic view.

By default, the generic view DetailView uses a template called "<app name>/<model name>_detail.html" . In our example, it will use the "polls/question_detail.html" template. The template_name property is used to tell Django to use a specified template name instead of automatically generated default name. We also specified template_name for the results list View-This ensures that results and detail views have a different appearance when rendered, even if they are the same in the background DetailView.

Similarly, theListView uses a default template called "<app name>/<model name>_detail.html" ; we use template_name to tell the ListView to use our own "polls/index.html" template that already exists.

In the previous tutorial, the template file was provided with a context containing the question and latest_question_list variables. For DetailView , question variables are provided automatically-because we use the Django model (question), Django can determine a suitable name for the context variable 。 For the ListView, however, the automatically generated context variable is question_list. To override this behavior, we provide the Context_object_name property, which indicates that we want to use latest_question_list. As a replacement, you can change your template to match the new context variable--but it tells Django that it's much easier to use the variable name you want to use.

Start the server and use a new voting app based on a common view.

For more information about the common view, see the documentation for the common view.

When you are satisfied with the form and general view you have written, read the 5th part of the tutorial to learn how to test our voting app.

Create a polling site with Django (iv)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.