Letztes Mal haben wir in Django Tutorial (Blog-App erstellen) ⑥ - Artikeldetails / Bearbeiten / Löschen-Funktion die Bildschirme für jeden Artikel erstellt, bearbeitet und gelöscht. ..
Dieses Mal werden wir größere Anpassungen an der Vorlage vornehmen, aber wenn wir sie grob teilen, werden wir Folgendes tun.
Erstellen eines Bildschirms, der allen Seiten gemeinsam ist
Erstellen einer Navigationsleiste
Ändern Sie jede Vorlage
Löschen Sie unnötige Vorlagen und Prozesse
Nicht nur auf Django beschränkt, es gibt Orte auf der Homepage, die gemeinsam angezeigt werden, auch wenn sich der Bildschirm ändert. In Qiita ist die oben angezeigte grüne Navigationsleiste ein gutes Beispiel.
↓ Dies Es ist jedoch schwierig, dies jedes Mal in jede Vorlage zu schreiben. Wenn ich den Code einmal schreibe und beende, aber wenn ich an die Zeit denke, als die Korrektur vorgenommen wurde ...
Daher werden wir ** gemeinsame Vorlage ** als praktische Funktion von Django verwenden. Einfach ausgedrückt, werden die gemeinsamen Teile in einer Datei zusammengefasst. Der Teil, der sich von Bildschirm zu Bildschirm unterscheidet, besteht darin, dass verschiedene Vorlagen aufgerufen und verwendet werden.
Erstellen Sie dazu zunächst eine Datei direkt unter dem Vorlagenordner. Dieses Mal erstellen wir eine Datei mit dem Namen /template/base.html.
└── templates
├── base.html #hinzufügen
└── blog
├── index.html
├── post_confirm_delete.html
├── post_detail.html
├── post_form.html
└── post_list.html
Schreiben Sie eine gemeinsame Verarbeitung in diese Datei und die Teile, die sich für jeden Bildschirm unterscheiden Ich werde eine Datei wie post_detail.html aufrufen.
Der Inhalt wird so sein.
base.html
<!doctype html>
<html lang="ja">
<head>
<title>tmasuyamas Blog</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="{% url 'blog:post_list' %}">oben</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'blog:post_create' %}">Post</a>
</li>
</ul>
</div>
</nav>
<!--Der Inhalt jeder Vorlage wird in diesem Block aufgerufen-->
{% block content %} #Beachtung!
{% endblock %} #Beachtung!
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
</body>
</html>
Dieses Tutorial geht nicht detailliert auf das Frontend ein. Sie können Bootstrap verwenden, indem Sie Bootstrap vom CDN aus aufrufen, damit es gut aussieht. Die Navigationsleiste wird in
Ich möchte, dass Sie auf den Teil achten, in dem Sie "** # Achtung! **" notiert haben.
<!--Der Inhalt jeder Vorlage wird in diesem Block aufgerufen-->
{% block content %} #Beachtung!
{% endblock %} #Beachtung!
Beim Aufrufen von Vorlagen gemäß Ansicht wird jede Vorlage hier gespeichert. Um es anders herum auszudrücken, muss jede Vorlage nur die charakteristischen Teile auf jede Seite schreiben.
Darüber hinaus muss die übergeordnete Vorlage (base.html) in der aufgerufenen Vorlage angegeben werden. Die grundlegende Schreibmethode ist wie folgt.
Jede Vorlage
{% extends 'base.html' %} #Angeben der übergeordneten Vorlage
{% block content %} #Beginnen Sie mit der Beschreibung des Inhalts
...Beschreibung für jede Vorlage...
{% endblock %} #Ende der Inhaltsbeschreibung
Jetzt können Sie die Rollen der übergeordneten und der untergeordneten Vorlage klar trennen. Als nächstes erkläre ich die Navigationsleiste, die von der übergeordneten Vorlage erstellt wurde.
Unter Verwendung der obigen base.html wird die folgende Navigationsleiste angezeigt. Dieses Mal beziehe ich mich auf Cheat Sheat von Bootstrap4. https://hackerthemes.com/bootstrap-cheatsheet/#navbar
Wählen Sie ** Oben **, um zum Bildschirm post_list.html zu gelangen. Wenn Sie ** Post ** auswählen, werden Sie zum Bildschirm post_form.html (neuer Post-Bildschirm) weitergeleitet.
Der Teil von base.html zum Anzeigen der Navigationsleiste war hier.
base.html
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="{% url 'blog:post_list' %}">oben</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'blog:post_create' %}">Post</a>
</li>
</ul>
</div>
</nav>
Der wichtige Teil hier ist ** "href =" {% url'blog: post_list '%} "" **.
Bisher hat die Vorlage den Link nicht beschrieben. Wenn Sie eine umgekehrte URL im obigen Format schreiben Sie werden nun zu der URL weitergeleitet, die entspricht.
urls.py
...
path('post_list', views.PostListView.as_view(), name='post_list'),
...
Vielen Dank, dass Sie jeder URL hier einen Namen wie ** name = 'post_list' ** geben Durch Angabe des Namens auf der Vorlagenseite wird dieser automatisch weitergeleitet.
Passen wir nun das Erscheinungsbild mit Bootstrap an, während wir die übergeordnete Vorlage für jede Vorlage angeben. Ich werde das ausgefüllte Formular einfügen.
post_detail.html
{% extends 'base.html' %}
{% block content %}
<table class="table">
<tr>
<th>Titel</th>
<td>{{ post.title }}</td>
</tr>
<tr>
<th>Text</th>
<!--Wenn Sie linebreaksbk einfügen, wird es ordnungsgemäß mit einem Zeilenumbruch-Tag angezeigt.-->
<td>{{ post.text | linebreaksbr}}</td>
</tr>
<tr>
<th>Datum</th>
<td>{{ post.date }}</td>
</tr>
</table>
{% endblock %}
post_form.html
{% extends 'base.html' %}
{% block content %}
<p>{{ post.title }}</p>
<!--Senden Sie Informationen an action an welche URL auf dem Server-->
<!--Wenn Sie die Aktion leer lassen, wird die aktuell geöffnete URL angezeigt= /blog/post_Gibt einen Wert für create, also views zurück.pys PostCreateView wird erneut aufgerufen-->
<form action="" method="POST">
<table class="table">
<tr>
<th>Titel</th>
<td>{{ form.title }}</td>
</tr>
<tr>
<th>Text</th>
<td>{{ form.text }}</td>
</tr>
</table>
<button type="submit" class="btn btn-primary">Senden</button>
{% csrf_token %}
</form>
{% endblock %}
post_confirm_delete.html
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">
<table class="table">
<tr>
<th>Titel</th>
<td>{{ post.title }}</td>
</tr>
<tr>
<th>Text</th>
<td>{{ post.text }}</td>
</tr>
<tr>
<th>Datum</th>
<td>{{ post.date }}</td>
</tr>
</table>
<p>Löschen Sie diese Daten.</p>
<button type="submit">Senden</button>
{% csrf_token %}
</form>
{% endblock %}
post_list.html
{% extends 'base.html' %}
{% block content %}
<table class="table">
<thead>
<tr>
<th>Titel</th>
<th>Datum</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for post in post_list %}
<tr>
<!-- 「url 'App Name:URL umkehren'Modell bestanden.Wie zeichnet man "pk"-->
<td><a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a></td>
<td>{{ post.date }}</td>
<td>
<!--Wird nur angezeigt, wenn Sie als Superuser angemeldet sind-->
{% if user.is_superuser %}
<!--Name der HTML-App_Modellname_Wenn Sie es ändern, können Sie es so bearbeiten, wie es mit admin ist-->
<a href="{% url 'blog:post_update' post.pk %}">Bearbeiten</a>
{% endif %}
</td>
<td>
{% if user.is_superuser %}
<a href="{% url 'blog:post_delete' post.pk %}">Löschen</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Die letzte post_list.html enthält einige zusätzliche Änderungen.
Eine besteht darin, Details für jeden in der Liste angezeigten Artikel hinzuzufügen, zu bearbeiten und zu löschen. Wenn das Verbindungsziel basierend auf dem Primärschlüssel bestimmt wird, können Sie den Primärschlüssel in Form von ** Variablenname.pk ** angeben.
Denken Sie daran, dass das durch den Namen der umgekehrten URL angegebene Formular eine feste Schreibweise ist.
<a href="{% url 'blog:post_detail' post.pk %}">...
Auch wenn dieses Tutorial die Benutzerregistrierungsfunktion nicht implementiert, Begrenzen Sie den Artikel so, dass niemand ihn bearbeiten oder löschen kann.
Diesmal gibt es also nur Superuser Nur wenn Sie über den Administratorbildschirm (127.0.0.1:8000/admin) als Superuser angemeldet sind Zeigt Links zum Bearbeiten und Löschen von Artikeln an.
{% if user.is_superuser %} #Zeigen Sie den Inhalt der if-Anweisung nur an, wenn Sie als Superuser angemeldet sind
<a href="{% url 'blog:post_update' post.pk %}">Bearbeiten</a>
{% endif %}
Oben war es die Zeit des Superusers, aber die Anzeige beim Anmelden als ein anderer Benutzer, Es ist auch möglich, es nur anzuzeigen, wenn Sie als bestimmter Benutzer angemeldet sind.
Nun, ich habe eine index.html-Seite hinterlassen, nur um Hallo zum Üben anzuzeigen. Wenn Sie mehr als dies verlassen, dauert die Verwaltung länger. Löschen Sie es daher zu diesem Zeitpunkt.
└── templates
├── base.html
└── blog
├── index.html #Lösch das
├── post_confirm_delete.html
├── post_detail.html
├── post_form.html
└── post_list.html
Vergessen Sie nicht, auch urls.py test_urls.py ,, views.py, test_views.py zu bearbeiten.
urls.py
...
urlpatterns = [
path('', views.IndexView.as_view(), name='index'), #Hier löschen
...
test_urls.py
...
class TestUrls(TestCase):
"""Getestete Weiterleitung beim Zugriff per URL auf die Indexseite"""
def test_post_index_url(self): #Entfernen Sie diese Methode vollständig
view = resolve('/blog/')
self.assertEqual(view.func.view_class, IndexView)
class TestUrls(TestCase):
"""Getestete Weiterleitung beim Zugriff per URL auf die Indexseite"""
def test_post_index_url(self): #Entfernen Sie diese Methode
view = resolve('/blog/')
self.assertEqual(view.func.view_class, IndexView)
...
views.py
...
class IndexView(generic.TemplateView): #Löschen Sie diese generische Ansicht
template_name = 'blog/index.html'
...
test_views.py
...
class IndexTests(TestCase): #Löschen Sie diese Testklasse
"""IndexView-Testklasse"""
def test_get(self):
"""Bestätigen Sie, dass der Statuscode 200 zurückgegeben wird, indem Sie mit der GET-Methode zugreifen."""
response = self.client.get(reverse('blog:index'))
self.assertEqual(response.status_code, 200)
...
Wir haben die Änderungen auf einmal vorgenommen. Lassen Sie uns nun endlich einen Komponententest durchführen, um festzustellen, ob Fehler vorliegen.
(blog) bash-3.2$ python3 manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..............E
======================================================================
ERROR: blog.tests.test_urls (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: blog.tests.test_urls
Traceback (most recent call last):
File "/usr/local/Cellar/[email protected]/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/Cellar/[email protected]/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "/Users/masuyama/workspace/MyPython/MyDjango/blog/mysite/blog/tests/test_urls.py", line 3, in <module>
from ..views import IndexView, PostListView
ImportError: cannot import name 'IndexView' from 'blog.views' (/Users/masuyama/workspace/MyPython/MyDjango/blog/mysite/blog/views.py)
----------------------------------------------------------------------
Ran 15 tests in 0.283s
FAILED (errors=1)
Destroying test database for alias 'default'...
Ein Fehler wurde bestätigt. Da die Fehlermeldung mithilfe von Trennzeichen usw. angezeigt wird, kann leicht festgestellt werden, wo der Fehler auftritt.
Wenn Sie der Fehlermeldung folgen, werden Sie feststellen, dass einige test_urls.py nicht importiert werden können und dass ein Fehler aufgetreten ist.
ImportError: cannot import name 'IndexView' from 'blog.views'
Als ich test_urls.py erneut las, stellte ich fest, dass die IndexView am Anfang geladen blieb.
test_urls.py
from django.test import TestCase
from django.urls import reverse, resolve
from ..views import IndexView, PostListView #Diese Linie
Löschen Sie dies und gehen Sie wie folgt vor.
test_urls.py
from django.test import TestCase
from django.urls import reverse, resolve
from ..views import PostListView
Lassen Sie uns nun den Komponententest erneut ausführen.
(blog) bash-3.2$ python3 manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
...............
----------------------------------------------------------------------
Ran 15 tests in 0.223s
OK
Destroying test database for alias 'default'...
Diesmal wurde der Test fehlerfrei abgeschlossen. Die Anzahl der Tests beträgt 15, was mit der Reduzierung von 2 Testmethoden gegenüber den vorherigen 17 Tests übereinstimmt.
Bisher habe ich nur das Ergebnis des Bestehens des Unit-Tests gezeigt, Auch wenn Änderungen in mehreren Dateien gleichzeitig auftreten, wie diesmal Ich hoffe, Sie haben herausgefunden, dass Sie den Problembereich mit einem einzigen Befehl identifizieren können, wenn Sie einen Komponententest im Voraus vorbereiten.
Sie haben eine lokale Django-App erfolgreich abgeschlossen!
Lassen Sie uns das nächste Mal die App, die wir dieses Mal gemacht haben, zu einem Docker machen, wenn es darum geht, die Umgebung zu verbessern.
Recommended Posts