Dernière fois Deux fois avant Première écriture
La dernière fois, j'ai ajouté la fonction de l'application polls
et elle fonctionne comme une application de vote.
Enfin, nous avons testé et corrigé le bogue, et la dernière fois était terminée.
Cette fois, je vais jeter un œil au contenu des tutoriels Django 5-7.
J'ai corrigé le bogue was_published_recently
dans le test que j'ai créé la dernière fois, mais comme ce correctif de bogue n'a ni origine ni enfant pour affecter d'autres parties, je vais le tester.
Ajoutez ce qui suit sous la classe QuestionModelTests
dans tests.py
.
mysite/polls/tests.py
def test_was_published_recently_with_old_question(self):
#Représente hier
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
#Représente la dernière minute
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
was_published_recently ()
est plus qu'hier et renvoie maintenant ce qui suit avec True
, donc test_was_published_recently_with_old_question ()
devrait être False
et test_was_published_recently_with_recent_question ()
devrait revenir avec True
.
Cette prédiction est dans self.assertIs
, donc je vais vérifier si elle est vraie.
cmd
(Django) C:\User\mysite>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s
OK
Destroying test database for alias 'default'...
Ainsi, Ran 3 tests in 0.002s
s'affiche, et vous pouvez voir que 3 tests ont réussi, y compris ceux que j'ai écrits la dernière fois.
Selon le tutoriel, cette application de vote a encore des bugs.
Cela chevauche la partie problématique de was_published_recently
, mais cela signifie que même les questions qui étaient pub_date
à une date et une heure futures seront affichées dans la vue.
Cette fois, nous allons construire un environnement de test en utilisant un shell interactif.
cmd
>>> from django.test import Client
>>> # create an instance of the client for our use
>>> client = Client()
>>> from django.urls import reverse
>>> response = client.get(reverse('polls:index'))
Ceci termine l'installation du client de test.
Dans le didacticiel, client.get ('/')
est exécuté avant cela pour détecter l'erreur, mais il est omis ici.
Et que contient la réponse
...
cmd
>>> response.status_code
200
>>> response.content </ul>\n'
b'\n <ul>\n \n <li><a href="/polls/1/">What's new?</a></li>\n \n </ul>\n'
>>> response.context['latest_question_list']
<QuerySet [<Question: What's new?>]>
C'est comme ça.
D'où vient le contenu de «response.content»?
J'ai lu la documentation officielle, mais je n'ai pas compris.
Je sais que je tire quelque chose qui ressemble à html
de quelque part, mais inversement, je ne sais que cela.
Jetons un second regard et améliorons la vue. Améliorez pour ne pas afficher les questions enregistrées dans la date et l'heure futures.
mysite/polls/views.py
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
#Réécrire cette fonction
def get_queryset(self):
#En dessous de la différence
return Question.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
pub_date__lte = timezone.now ()
pointe vers une pub_date
antérieure à la date et à l'heure actuelles.
__lte
signifie inférieur à égal, ce qui signifie quelque chose comme pub_date <= timezone.now ()
.
Nous allons créer un code de test comme celui écrit au moment de was_published_recently
et le préparer pour un test facile.
mysite/polls/tests.py
def create_question(question_text, days):
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_past_question(self):
create_question(question_text="Past question.", days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_future_question(self):
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_future_question_and_past_question(self):
create_question(question_text="Past question.", days=-30)
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question.>']
)
def test_two_past_questions(self):
create_question(question_text="Past question 1.", days=-30)
create_question(question_text="Past question 2.", days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(
response.context['latest_question_list'],
['<Question: Past question 2.>', '<Question: Past question 1.>']
)
Le code est plus long, mais il contient test_no_question ()
s'il n'y a pas de questions, test_past_question
si la question a été ajoutée dans le passé, etsi la question a été ajoutée ultérieurement. Test_future_question ()
, test_future_question_and_past_question
quand il y a deux questions ajoutées dans le passé et le futur, et test_two_past_questions ()
quand les deux questions ont été ajoutées dans le passé. Il est écrit.
create_question
définit le processus de création d'une question dans un test en tant que fonction.
Espérons qu'il réussira comme suit: Une fois que j'ai eu FAIL
, même si j'ai corrigé le code après cela, cela ne fonctionnait pas dans le même terminal. Donc, si vous faites une erreur et que vous voulez recommencer, il peut être préférable de monter un autre terminal.
cmd
(Django) C:\User\mysite>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..........
----------------------------------------------------------------------
Ran 8 tests in 0.044s
OK
Destroying test database for alias 'default'...
L'amélioration du test précédent est que ʻIndexViewn'affichera pas les questions publiées à l'avenir, mais si vous le tirez par URL,
DetailViewsera toujours affiché. Nous allons donc résoudre ce problème. Tout d'abord, ajoutez la méthode
get_queryset ()à la classe
DetailView de la même manière que l'ajout de ʻIndexView
.
mysite/polls/views.py
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())
Après cela, le didacticiel est en anglais pour une raison quelconque, mais au fur et à mesure qu'il est écrit, j'ai ajouté un test pour vérifier que pub_date
montre les précédents et non les futurs. Cela signifie que vous devez.
mysite/polls/test.py
class QuestionDetailViewTests(TestCase):
def test_future_question(self):
future_question = create_question(question_text='Future question.', days=5)
url = reverse('polls:detail', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_past_question(self):
past_question = create_question(question_text='Past Question.', days=-5)
url = reverse('polls:detail', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)
Cela peut être interprété de la même manière que pour ʻIndexView.
test_future_question vérifie si
pub_date n'affiche pas les futures comme
DetailView, et
test_past_questionvérifie si
pub_date montre les anciennes dans
DetailView`.
Ceci est également testé et ressemble à ceci: Comme le nombre total de tests jusqu'à présent est de 10, le résultat du test doit être de 10 tests, donc le résultat doit être «Ran 10 tests».
cmd
(Django) C:\User\mysite>python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..........
----------------------------------------------------------------------
Ran 10 tests in 0.058s
OK
Destroying test database for alias 'default'...
En regardant jusqu'ici, il semble que vous puissiez faire un test pour ResultView
tel quel.
Le tutoriel était limité aux suggestions, mais écrivons-en une ici.
mysite/polls/test.py
class QuestionResultViewTests(TestCase):
def test_future_question(self):
future_question = create_question(question_text='Future question.', days=5)
url = reverse('polls:results', args=(future_question.id,))
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_past_question(self):
past_question = create_question(question_text='Past Question.', days=-5)
url = reverse('polls:results', args=(past_question.id,))
response = self.client.get(url)
self.assertContains(response, past_question.question_text)
En fait, c'est presque la même chose que quand c'était DetailView
. La seule chose qui a changé est ʻurl = reverse ('polls: results', args = ..) `.
Aussi, mettons correctement get_queryset
dans ResultsView
de views.py
.
Comme ça
mysite/polls/views.py
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())
C'est la fin du test du tutoriel, mais il semble que Django dispose également d'une fonction pour tester le comportement de l'écran créé par HTML. C'est vraiment sophistiqué.
De là, vous pouvez accéder au didacticiel 6.
Jusqu'à présent, je n'ai pas utilisé de CSS ou de JavaScript qui apparaissent souvent dans la création de pages Web, mais Django peut bien les utiliser. Django traite ces fichiers comme des fichiers statiques.
Il semble que django.contrib.staticfiles
puisse gérer de manière centralisée ces fichiers statiques pour chaque application.
Créez un dossier static
sous polls
pour que Django gère les fichiers statiques. Créez un autre dossier polls
sous static
comme vous l'avez fait lorsque vous avez créé le dossier template
.
Ensuite, j'écrirai le CSS suivant.
mysite/polls/static/polls/style.css
li a {
color: green;
}
Ensuite, ajoutez également une référence à CSS dans ʻindex.html`.
mysite/polls/templates/polls/index.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
Écrivez cette déclaration en haut du fichier. {% static%}
est une balise de modèle Django qui indique l'emplacement des fichiers statiques.
Quand je le vérifie, ...
C'est définitivement vert, mais la différence est trop subtile (rires)
Nous ajouterons des paramètres à style.css
pour ajouter une image d'arrière-plan.
mysite/polls/static/polls/style.css
body {
background: white url("images/background.png ") no-repeat;
}
Comme vous pouvez le voir sur le lien, il fait référence à l'image background.png
sous le dossier mysite / polls / static / polls / image /
, alors mettez le fichier correspondant à l'avance. L'image ne sera pas affichée sans elle.
Donc, voici le résultat de l'introduction d'une image appropriée d'Irasutoya.
C'était bien affiché!
J'ai confirmé que vous pouvez ajouter Question
depuis l'écran de l'administrateur il y a quelques fois (EP1-2), mais dans Django cet écran Vous pouvez même le personnaliser.
Dans le didacticiel, essayez le code pour jouer avec l'écran de personnalisation des questions.
mysite/polls/admin.py
from django.contrib import admin
from .models import Question
# Register your models here
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date']}),
]
admin.site.register(Question, QuestionAdmin)
Les changements sont l'ajout de la classe QuestionAdmin
et l'ajout de QuestionAdmin
à l'argument de ʻadmin.site.register ()`.
Désormais, lorsque vous vous connectez en tant qu'administrateur et que vous entrez dans l'écran de changement de question, les champs sont séparés comme indiqué ci-dessous.
Pour le moment, vous ne pouvez voir que la question, mais vous pouvez également voir chaque option qui accompagne la question.
mysite/polls/admin.py
from .models import Choice, Question
admin.site.register(Choice)
Les changements sont que Choice
est également ʻimport from
models et ʻadmin.site.register (Choice)
est ajouté.
Quand je le vérifie, tout d'abord, vous pouvez sélectionner Choice
au début comme ceci
Sélectionnez ensuite «Choix» pour accéder à l'écran de sélection. Ensuite, vous atteindrez l'écran de réglage suivant.
C'est encore assez bon, mais comme «Choix» est lié à «Question», cela semble-t-il plus facile à utiliser si vous pouvez le modifier ensemble?
Par conséquent, je vais arrêter ʻadmin.site.register (Choice) `et le modifier davantage.
mysite/polls/admin.py
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
Ajoutez la classe ChoiceInline
et ajoutez la partie qui la reçoit dans la classe QuestionAdmin
. Supprimez ʻadmin.site.register (Choice) `.
Ensuite, vous pourrez modifier «Choix» sur l'écran «Question» comme indiqué ci-dessous.
Ensuite, nous allons rendre cet écran, qui est le point précédent de l'écran de réglage «Question», plus facile à utiliser.
Je n'ai pas trouvé cela gênant à utiliser, mais j'ajouterai un nouveau code à ʻadmin.pyet
models.py` pour le rendre encore plus pratique.
mysite/polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
#La phrase supplémentaire suivante
list_display = ('question_text', 'pub_date', 'was_published_recently')
list_filter = ['pub_date']
search_fields = ['question_text']
mysite/polls/models.py
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self) -> str:
return self.question_text
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
#La phrase supplémentaire suivante
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
Le contenu affiché par list_display
a été développé, et le filtre de la barre latérale est maintenant efficace avec list_filter
, et vous pouvez également rechercher avec search_fields
. (Les principaux changements sont dans la boîte)
L'écran administrateur peut également être personnalisé en utilisant le fichier html
comme dans le cas de ʻIndexView. Pour être honnête, la valeur par défaut est suffisante, mais il peut être pratique de l'utiliser un jour. Tout d'abord, indiquez à
setting.py le chemin du
modèle` auquel ce projet fait référence.
mysite/mysite/setting.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], #Cette ligne! !! !!
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
En fait, la copie et le collage du code de ce didacticiel ont échoué. Dans le tutoriel, il s'agit de `` DIRS ': [BASE_DIR /' templates '], mais cela est considéré comme un calcul de type chaîne de caractères, et bien sûr la chaîne de caractères ne peut pas être divisée, donc une erreur se produira. J'ai donc spécifié le chemin en définissant ʻos.path.join (BASE_DIR, 'templates')], `pour éviter l'erreur. La lecture du tutoriel en anglais ne m'a pas donné de réponse ici. Y a-t-il un problème avec le didacticiel? Je pense que c'est mon oubli, mais ...
Ensuite, tirez le modèle sur l'écran d'administration à partir du fichier source Django. Il existe également un exemple de Template dans le package Django. amical. Vous pouvez vérifier où se trouve le fichier source Django avec le code suivant.
cmd
(Django) C:\Users\mysite> python -c "import django; print(django.__path__)"
Une fois que vous connaissez l'emplacement, ouvrez-le avec l'Explorateur et placez base_site.html
sous mysite / templates / admin
.
Créez un nouveau dossier templates
et le dossier ʻadmin en dessous ici. (
Base_site.html est dans
django / contrib / admin / templates / admindans le fichier source) Puis éditez un peu
base_site.html`.
mysite/templates/admin/base_site.html
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Écran administrateur</a></h1>
{% endblock %}
Si vous extrayez uniquement la pièce modifiée, elle sera ici. Si vous mettez un caractère dans la balise <a> <\ a>
, il apparaîtra en haut de la page.
Par défaut, {{site_header | default: _ ('Django administration')}}
est inclus.
Vérifiez ensuite si les modifications sont reflétées comme suit. Cela a bien changé! !!
Ceci conclut le didacticiel Django. Il y en avait beaucoup. Pour être honnête, même si vous venez ici, il est toujours impossible de lâcher prise (rires) Cependant, si vous comprenez les bases, je pense qu'une étude plus approfondie fera de grands progrès. C'était un contenu tellement moelleux. Il y a un tutoriel avancé après cela, mais je ne l'ai pas encore fait (rires) Quand vous en avez besoin ...
La prochaine fois, j'étudierai Git en tournant un peu plus Django, alors merci.