Cet article est une série qui fait progresser le didacticiel officiel de Django. Cette fois, nous allons procéder avec le 4ème article "Création de votre première application Django, partie 4".
Résumé du tutoriel Django pour les débutants par les débutants ① (création de projet ~) Résumé du tutoriel Django pour les débutants par les débutants ② (Modèle, Admin) Résumé du tutoriel Django pour les débutants par les débutants ③ (Afficher) Résumé du tutoriel Django pour les débutants par les débutants ④ (Vue générique) Résumé du tutoriel Django pour les débutants par les débutants ⑤ (test) Résumé du tutoriel Django pour les débutants par les débutants ⑥ (fichier statique) Résumé des tutoriels Django pour les débutants par les débutants ⑦ (Customize Admin)
https://docs.djangoproject.com/ja/3.0/intro/tutorial04/
Write a minimal form
Placez le formulaire de vote dans le detail.html
créé dans l'article précédent.
polls/templates/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
est une valeur qui indique combien de fois la boucle de la balise for a été exécutée.
Si vous regardez le contenu, vous pouvez voir que tous les choix liés à Question sont affichés sous forme de choix de bouton radio dans l'instruction for.
Vous devez insérer {% csrf_token%}
lors de la création d'un formulaire POST pour les mesures CSRF.
Puis éditez polls / views.py
pour que le vote fonctionne bien.
polls/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question
# ...
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):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
Par request.POST ['choice']
, la valeur POSTed par le nom de'choice 'dans le formulaire ci-dessus est lue comme selected_choice
.
Une KeyError est lancée lorsque request.POST ['choice']
n'existe pas (c'est-à-dire si l'utilisateur ne sélectionne rien).
Dans ce cas, le formulaire sera à nouveau rendu avec un message d'erreur.
Lorsque le processus est terminé normalement, il redirige vers les résultats. (La redirection doit être appliquée lorsque le traitement tel que POST est terminé normalement (quel que soit Django))
Vous pouvez empêcher le revêtement dur URL avec la fonction reverse
.
L'utilisation est similaire à la spécification d'URL utilisée dans ʻindex.html`.
Maintenant, ajoutez la vue des résultats à polls / views.py
.
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})
Le contenu est presque le même que la vue du «détail».
Créons également un modèle.
polls/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>
Avez-vous remarqué qu'il y a un problème jusqu'à présent?
Dans le flux de traitement actuel, récupérez d'abord selected_choice
de DB, calculez une nouvelle valeur à partir de ses votes et enregistrez-la dans DB.
Même si la valeur des voix était à l'origine de 42, si MM. A et B votent en même temps, la place qui devrait initialement être de 44 devient 43.
Il semble qu'un tel problème s'appelle un "problème de conflit", et l'article suivant sera utile pour l'explication de F ()
pour le résoudre.
Tous les enregistrements jusqu'à ce qu'oncle Java puisse utiliser Python (n ° 16)
Django a un raccourci appelé Vue générale (vue générique)
Récupère les données de la base de données en fonction des paramètres passés via l'URL, charge le modèle et renvoie le modèle rendu. Ceci est si courant que Django propose un raccourci appelé la vue générique. Une vue générique est une abstraction de modèles courants qui vous permet d'écrire une application sans même écrire de code Python.
... Apparemment ...
Modifiez polls / urls.py
comme suit
polls/urls.py
from 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'),
]
La différence est que views.IndexView.as_view ()
etc. est passé à la vue spécifiée par path.
De plus, «question_id» a été renommé en «pk». (La raison sera décrite plus tard)
Créez la classe ʻIndexView` etc. dans la vue.
polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, 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'
def vote(request, question_id):
... # same as above, no changes needed.
«ListView» et «DetailView» sont utilisés.
Le question_id
a été renommé en pk
car il est spécifié comme tel dans DetailView
.
Par défaut, la vue générique DetailView
utilise un modèle nommé <nom de l'application> / <nom du modèle> _detail.html, mais vous pouvez changer le modèle utilisé en spécifiant l'attribut nom_modèle
. (Idem pour ListView
)