---
# System prepended metadata

title: Тема 5. Формы для блога
tags: [Python Web]

---

---
tags: Python Web
source: https://python-scripts.com/django-forms
---

# Тема 5. Формы для блога

https://github.com/roman-yatsenko/django-topics/tree/main/django-forms

## Форма для создания записи на блоге (CreateView)

### `templates\base.html`

```htmlmixed=9
<header>
  <div class="nav-left">
    <h1><a href="{% url 'home' %}">Django blog</a></h1>
  </div>
  <div class="nav-right">
    <a href="{% url 'post_new' %}">+ New Blog Post</a>
  </div>
</header>
```

### `static\css\base.css`

```css=6
header {
  border-bottom: 1px solid #999;
  margin-bottom: 2rem;
  display: flex;
}
 
.nav-left {
  margin-right: auto;
}
 
.nav-right {
  display: flex;
  padding-top: 2rem;
}
```

### `blog\urls.py`

```python=
from django.urls import path
 
from .views import BlogListView, BlogDetailView, BlogCreateView # new
 
urlpatterns = [
    path('post/new/', BlogCreateView.as_view(), name='post_new'), # new
    path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
    path('', BlogListView.as_view(), name='home'),
]
```

### `blog\views.py`

```python=
from django.views.generic import ListView, DetailView 
from django.views.generic.edit import CreateView # new
```

```python=17
class BlogCreateView(CreateView): # new
    model = Post
    template_name = 'post_new.html'
    fields = ['title', 'author', 'body']
```

### `templates\post_new.html`

```shell
touch templates/post_new.html
```

```htmlmixed=
{% extends 'base.html' %}
 
{% block content %}
    <h1>New post</h1>
    <form action="" method="post">{% csrf_token %}
      {{ form.as_p }}
      <input type="submit" value="Save" />
    </form>
{% endblock content %}
```

```shell
python manage.py runserver
```

### `blog\models.py`

```python=
from django.db import models
from django.urls import reverse # new
```

```python=15
    def get_absolute_url(self): # new Post method
        return reverse('post_detail', args=[str(self.id)])
```

## Форма для обновления данных (UpdateView)

### `templates\post_detail.html`

```htmlmixed=9
  <a href='{% url 'post_edit' post.pk %}'>+ Edit Blog Post</a>
{% endblock content %}
```

```shell
touch templates/post_edit.html
```

### `templates\post_edit.html`

```htmlmixed=
{% extends 'base.html' %}
 
{% block content %}
    <h1>Edit post</h1>
    <form action="" method="post">{% csrf_token %}
      {{ form.as_p }}
    <input type="submit" value="Update" />
</form>
{% endblock content %}
```

### `blog\views.py`

```python=
from django.views.generic import ListView, DetailView 
from django.views.generic.edit import CreateView, UpdateView # new
```

```python=22
class BlogUpdateView(UpdateView): # new
    model = Post
    template_name = 'post_edit.html'
    fields = ['title', 'body']
```

### `blog\urls.py`

```python=
from django.urls import path
 
from .views import (
    BlogListView,
    BlogDetailView,
    BlogCreateView,
    BlogUpdateView, # new
)
 
urlpatterns = [
    path('post/<int:pk>/edit/',  BlogUpdateView.as_view(), name='post_edit'), # new
    path('post/new/', BlogCreateView.as_view(), name='post_new'),
    path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
    path('', BlogListView.as_view(), name='home'),
]
```

```shell
python manage.py runserver
```

## Страница удаления записи (DeleteView)

### `templates\post_detail.html`

```htmlmixed=9
  <p><a href="{% url 'post_edit' post.pk %}">+ Edit Blog Post</a></p>
  <p><a href="{% url 'post_delete' post.pk %}">+ Delete Blog Post</a></p>
{% endblock content %}
```

```shell
touch templates/post_delete.html
```

### `templates\post_delete.html`

```htmlmixed=
{% extends 'base.html' %}
 
{% block content %}
    <h1>Delete post</h1>
    <form action="" method="post">{% csrf_token %}
      <p>Are you sure you want to delete "{{ post.title }}"?</p>
      <input type="submit" value="Confirm" />
    </form>
{% endblock content %}
```

### `blog\views.py`

```python=
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView # new
from django.urls import reverse_lazy # new
```

```python=30
class BlogDeleteView(DeleteView): # new
    model = Post
    template_name = 'post_delete.html'
    success_url = reverse_lazy('home')
```

### `blog\urls.py`

```python=3
from .views import (
    BlogListView,
    BlogUpdateView,
    BlogDetailView,
    BlogCreateView,
    BlogDeleteView, # new
)
 
urlpatterns = [
    path('post/<int:pk>/delete/', # new
    BlogDeleteView.as_view(), name='post_delete'),
    path('post/new/', BlogCreateView.as_view(), name='post_new'),
    path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
    path('post/<int:pk>/edit/',
    BlogUpdateView.as_view(), name='post_edit'),
    path('', BlogListView.as_view(), name='home'),  
]
```

```shell
python manage.py runserver
```

## Тестируем добавление, обновление и удаление записей

### `blog\tests.py`

```python=46
    def test_get_absolute_url(self): # new
        self.assertEqual(self.post.get_absolute_url(), '/post/1/')

    def test_post_create_view(self): # new
        response = self.client.post(reverse('post_new'), {
            'title': 'New title',
            'body': 'New text',
            'author': self.user,
        })
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'New title')
        self.assertContains(response, 'New text')
 
    def test_post_update_view(self): # new
        response = self.client.post(reverse('post_edit', args='1'), {
            'title': 'Updated title',
            'body': 'Updated text',
        })
        self.assertEqual(response.status_code, 302)
 
    def test_post_delete_view(self): # new
        response = self.client.post(
            reverse('post_delete', args='1'))
        self.assertEqual(response.status_code, 302)
```

```shell
python manage.py test
```

---

(c) Яценко Р.Н., 2018-2020

[Учебный центр компьютерных технологий "Кит"](http://kit.kh.ua/)

<img src="https://i.imgur.com/Kh901c1.png" style="width: 150px; position: fixed; top: 100px; right: 10px; border: 0; box-shadow: none;">
