[PYTHON] Django-Tutorial (Blog-App erstellen) Ar - Artikeldetails / Funktionen bearbeiten / löschen

Letztes Mal in Django Tutorial (Blog-App erstellen) ⑤ - Artikelerstellungsfunktion Es wurde die Möglichkeit hinzugefügt, Artikel in der App zu erstellen.

Jetzt, da wir C (Erstellen) in CRUD ausführen können, werden wir die verbleibenden Funktionen (Details, Bearbeiten, Löschen) hinzufügen.

Wir werden auch die Detailanzeige-, Bearbeitungs- und Löschfunktionen von Artikeln in der klassenbasierten Allzweckansicht implementieren.

Korrigieren Sie urls.py

In den Funktionen, die von nun an enthalten sein sollen, können Sie basierend auf dem eindeutigen Schlüssel jedes Artikels zugreifen und diese bearbeiten. Der Schlüsselwert ist der ** Primärschlüssel ** jedes Artikels.

Mit der klassenbasierten generischen Ansichtsfunktion von Django können Sie das Routing in urls.py konfigurieren. Sie können das URL-Muster mit dem Zeichenfolgenprimärschlüssel ** <int: pk> ** für jeden Artikel angeben.

Legen Sie beispielsweise in der detaillierten Anzeigefunktion einfach das URL-Muster 'blog / post_detail / <int: pk>' fest. Der erstellte Artikel kann anhand des Primärschlüssels identifiziert und an die Ansicht weitergeleitet werden, die Details, Bearbeitung und Löschung steuert.

Legen Sie den Namen der Ansichtsklasse mit den folgenden Namen fest.

--Details: PostDetailView --Edit: PostUpdateView --Delete: PostDeleteView

Zu diesem Zeitpunkt sieht urls.py folgendermaßen aus:

urls.py


from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('post_list', views.PostListView.as_view(), name='post_list'),
    path('post_create', views.PostCreateView.as_view(), name='post_create'),
    path('post_detail/<int:pk>/', views.PostDetailView.as_view(), name='post_detail'), #hinzufügen(Beispiel) /blog/detail/1 * Da die Verarbeitung für einen bestimmten Datensatz durchgeführt wird, kann sie durch pk identifiziert werden.
    path('post_update/<int:pk>/', views.PostUpdateView.as_view(), name='post_update'), #hinzufügen(Beispiel) /blog/update/1 * Wie oben
    path('post_delete/<int:pk>/', views.PostDeleteView.as_view(), name='post_delete'), #hinzufügen(Beispiel) /blog/delete/1 * Wie oben
]

Sie können sehen, dass Details, Aktualisierungen und Löschungen in jedem Artikel durch durch Schrägstriche getrennte Primärschlüssel angegeben werden.

(Wenn Sie ein lokaler Host sind, können Sie über Ihren Browser unter der URL ** 127.0.0.1:8000/blog/post_detail/1** darauf zugreifen.)

Ändern Sie views.py

Als nächstes erstellen wir jede Ansicht. Ich werde Ihnen zuerst das ausgefüllte Formular zeigen.

views.py


...
class PostDetailView(generic.DetailView): #hinzufügen
    model = Post  # pk(primary key)Ist URLs.Da es von py angegeben wird, müssen Sie hier nur model aufrufen
    
class PostUpdateView(generic.UpdateView): #hinzufügen
    model = Post
    form_class = PostCreateForm #PostCreateForm kann fast so verwendet werden, wie es ist
    success_url = reverse_lazy('blog:post_detail')
class PostDeleteView(generic.DeleteView): #hinzufügen
    model = Post
    success_url = reverse_lazy('blog:post_list')

Erklärung von PostDetailView

Sie könnten von der geringen Menge an Code überrascht sein. Sie müssen insbesondere nichts über den Primärschlüssel schreiben, und dank der Leistungsfähigkeit der generischen Ansicht können Sie damit eine Detailseite erstellen. Wenn Sie der Vorlage den Dateinamen ** post_detail.html ** geben, wird sie automatisch identifiziert.

PostUpdateView Tatsächlich ist UpdateView CreateView sehr ähnlich, da Sie dasselbe Formular verwenden können wie beim Erstellen eines neuen.

views.Erklärung von py


...
class PostCreateView(generic.CreateView):
    model = Post
    form_class = PostCreateForm
    success_url = reverse_lazy('blog:post_list')
...

Der einzige Unterschied besteht darin, dass die success_url zum Zeitpunkt der erfolgreichen Bearbeitung als Artikeldetails-Bildschirm in UpdateView verwendet wird. Wenn dies auch mit der Artikelliste (post_list) identisch ist, kann der Inhalt genau den gleichen Mantel haben.

Tatsächlich kann ** post_form.html **, das in PostCreate verwendet wird, so verwendet werden, wie es ist Es ist nicht erforderlich, eine neue Vorlage vorzubereiten.

Erklärung von PostDetailView

Beim Löschen wird kein Eingabeformular verwendet, sodass das Formular nicht aufgerufen werden muss. Es gibt jedoch zwei Dinge zu beachten, die sich von Update unterscheiden.

Zum einen lautet der Vorlagenname ** post_confirm_delete.html **. Aus dem bisherigen Ablauf geht hervor, dass es sich um post_delete.html handelt. Die Definition des Namens unterscheidet sich geringfügig, da er auch dann nicht plötzlich gelöscht wird, wenn Sie darauf zugreifen.

Das andere ist das Umleitungsziel, wenn das Löschen erfolgreich ist. In UpdateView war entweder der Listenbildschirm oder der Detailbildschirm in Ordnung. Achten Sie darauf, nicht zum Detailbildschirm (post_detail) umzuleiten, da durch das Löschen die Artikel entfernt werden, auf die Sie zugreifen möchten.

Vorbereitung der Vorlage

Erstellen Sie dann, wie ich in views.py ein wenig erwähnt habe, eine Vorlage (HTML) für Details und Löschen unter template / blog /.

└── templates
    └── blog
        ├── index.html
        ├── post_confirm_delete.html #hinzufügen
        ├── post_detail.html #hinzufügen
        ├── post_form.html
        └── post_list.html

Jetzt bearbeiten wir zuerst ** post_detail.html **.

post_detail.html


<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>

Die Variable ** post ** wird auf der Vorlagenseite empfangen und als {{post.title}} & {{post.text}} & {{post.date}} angezeigt. Wenn Sie nach post.text "| linebreaksbr" einfügen, werden auch lange Artikel wie der Hauptteil des Artikels automatisch beschädigt.

Dann bearbeiten Sie ** post_confirm_delete.html **.

post_confirm_delete.html


<form action="" method="POST">
  <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>

In der ersten Zeile wird die POST-Methode zum Löschen von Artikeln verwendet, daher gibt das Formular die POST-Methode an. Da die Verarbeitung wie das POST-Ziel auf der Ansichtsseite angepasst wird, muss es nicht auf der Vorlagenseite beschrieben werden. Achten Sie schließlich darauf, {% csrf_token%} in die CSRF-Kennzahlen zu schreiben.

Damit ist die Vorlagenbearbeitung abgeschlossen.

Erstellen eines Komponententests

Zuerst hinzufügen

test_views.py


...
class PostDetailTests(TestCase): #hinzufügen
    """PostDetailView-Testklasse"""

    def test_not_fount_pk_get(self):
        """Bestätigen Sie, dass 404 zurückgegeben wird, wenn Sie mit dem Primärschlüssel eines Artikels zugreifen, der im leeren Zustand nicht vorhanden ist, ohne den Artikel zu registrieren"""
        response = self.client.get(
            reverse('blog:post_detail', kwargs={'pk': 1}),
        )
        self.assertEqual(response.status_code, 404)

    def test_get(self):
        """Bestätigen Sie, dass der Statuscode 200 zurückgegeben wird, indem Sie mit der GET-Methode zugreifen."""
        post = Post.objects.create(title='test_title', text='test_text')
        response = self.client.get(
            reverse('blog:post_detail', kwargs={'pk': post.pk}),
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, post.title)
        self.assertContains(response, post.text)

class PostUpdateTests(TestCase): #hinzufügen
    """PostUpdateView-Testklasse"""

    def test_not_fount_pk_get(self):
        """"""
        response = self.client.get(
            reverse('blog:post_update', kwargs={'pk': 1}),
        )
        self.assertEqual(response.status_code, 404)

    def test_get(self):
        """Bestätigen Sie, dass der Statuscode 200 zurückgegeben wird, indem Sie mit der GET-Methode zugreifen."""
        post = Post.objects.create(title='test_title', text='test_text')
        response = self.client.get(
            reverse('blog:post_update', kwargs={'pk': post.pk}),
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, post.title)
        self.assertContains(response, post.text)

class PostDeleteTests(TestCase): #hinzufügen
    """PostDeleteView-Testklasse"""

    def test_not_fount_pk_get(self):
        """Bestätigen Sie, dass 404 zurückgegeben wird, wenn Sie mit dem Primärschlüssel eines Artikels zugreifen, der im leeren Zustand nicht vorhanden ist, ohne den Artikel zu registrieren"""
        response = self.client.get(
            reverse('blog:post_delete', kwargs={'pk': 1}),
        )
        self.assertEqual(response.status_code, 404)

    def test_get(self):
        """Bestätigen Sie, dass der Statuscode 200 zurückgegeben wird, indem Sie mit der GET-Methode zugreifen."""
        post = Post.objects.create(title='test_title', text='test_text')
        response = self.client.get(
            reverse('blog:post_delete', kwargs={'pk': post.pk}),
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, post.title)
        self.assertContains(response, post.text)

Die Bestätigung, dass die GET-Methode 200 zurückgibt, unterscheidet sich nicht wesentlich vom vorherigen Komponententest. Der Prozess, eine Antwort auf einen Artikel zu erhalten, der existieren sollte, ist sehr unterschiedlich.

...
def test_not_fount_pk_get(self):
    """Bestätigen Sie, dass 404 zurückgegeben wird, wenn Sie mit dem Primärschlüssel eines Artikels zugreifen, der im leeren Zustand nicht vorhanden ist, ohne den Artikel zu registrieren"""
    response = self.client.get(
        reverse('blog:post_delete', kwargs={'pk': 1}),
    )
    self.assertEqual(response.status_code, 404)
...

Ich habe bereits erwähnt, dass Sie im Unit-Test Daten in der Datenbank registrieren (hier einen Artikel erstellen) können. Wenn Sie jedoch versuchen, mit dem Primärschlüssel 1 = dem ersten Artikel, in dem der Artikel nicht vorhanden ist, auf den Bildschirm Details / Bearbeiten / Löschen des Artikels zuzugreifen

In der obigen Testmethode, auch wenn Sie es wagen, auf die einzelne Seite des Artikels, die nicht existiert, zuzugreifen und sie zu bedienen Ich bestätige, dass ein Fehler zurückgegeben wird.

Wenn Sie nun den Komponententest ausführen, sollte er fehlerfrei bestehen.

(blog) bash-3.2$ python3 manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.................
----------------------------------------------------------------------
Ran 17 tests in 0.460s

OK
Destroying test database for alias 'default'...

Nachdem Sie die CRUD-Funktion erfolgreich hinzugefügt haben, ist sie eine große Funktion.

Als Nächstes ändern wir die Vorlage und zeigen sie auf allen Seiten an, indem wir allen Bildschirmen eine gemeinsame Navigationsleiste hinzufügen.

→ Nächstes Mal Django-Tutorial (Blog-App erstellen) ⑦ - Vorderes Ende abgeschlossen

Recommended Posts

Django-Tutorial (Blog-App erstellen) Ar - Artikeldetails / Funktionen bearbeiten / löschen
Django Tutorial (Blog-App erstellen) ⑤ - Artikelerstellungsfunktion
Django Tutorial (Blog App erstellen) ③ - Artikellistenanzeige
Django Tutorial (Blog App erstellen) ④ --Einheitentest
Django Tutorial (Blog App erstellen) ① - Vorbereitung, Erstellung der obersten Seite
Django Tutorial (Blog App erstellen) ⑦ --Front End Complete
Django-Tutorial (Erstellung von Blog-Apps) ② - Modellerstellung, Vorbereitung der Verwaltungssite
Todo-App mit Django erstellen ④ Ordner- und Aufgabenerstellungsfunktion implementieren