Мне удалось перейти к седьмой главе книги «Разработка через тестирование на Python».
Я просмотрел все темы об одних и тех же ошибках в Google, но объяснения отличаются от моего теста. Поэтому я изо всех сил пытаюсь понять, что не так с кодом ниже. Я понимаю, что
AttributeError: 'NoneType' object has no attribute 'id'
говорит мне, 'id'
не определено. Но я не знаю, где это исправить в Джанго.
Также для
self.assertEqual(Item.objects.count(), 1)
AssertionError: 0 != 1,
Я не знаю, где искать.
(sup) ben@ben:~/sup1/superlists$ sudo python3 manage.py test lists
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
======================================================================
ERROR: test_redirects_after_POST (lists.tests.NewListTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tim/sup1/superlists/lists/tests.py", line 93, in test_redirects_after_POST
self.assertRedirects(response, f'/lists/{new_list.id}/')
AttributeError: 'NoneType' object has no attribute 'id'
======================================================================
FAIL: test_can_save_a_POST_request (lists.tests.NewListTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tim/sup1/superlists/lists/tests.py", line 87, in test_can_save_a_POST_request
self.assertEqual(Item.objects.count(), 1)
AssertionError: 0 != 1
MODELS.PY
from django.db import models
class List(models.Model):
pass
class Item(models.Model):
text = models.TextField(default='')
list = models.ForeignKey(List, default='', null=True, blank=True, on_delete = models.CASCADE)
TESTS.PY
from django.template.loader import render_to_string
from django.urls import resolve, reverse_lazy
from django.test import TestCase
from django.http import HttpRequest
from lists.views import home_page
from lists.models import Item, List
class HomePageTest(TestCase):
def test_uses_home_template(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'home.html')
def test_displays_all_list_items(self):
Item.objects.create(text='itemey 1')
# Item.objects.create(text='itemey 2')
response = self.client.get('/')
self.assertIn('item', response.content.decode())
# self.assertIn('itemey 2', response.content.decode())
def test_only_saves_items_when_necessary(self):
self.client.get('/')
self.assertEqual(Item.objects.count(), 0)
class ListViewTest(TestCase):
def test_uses_list_template(self):
list_ = List.objects.create()
response = self.client.get(f'/lists/{list_.id}/')
self.assertTemplateUsed(response, 'list.html')
def test_displays_only_items_for_that_list(self):
correct_list = List.objects.create()
Item.objects.create(text='item', list=correct_list)
# Item.objects.create(text='itemey 2', list=correct_list)
response = self.client.get(f'/lists/{correct_list.id}/')
self.assertContains(response, 'item')
# self.assertContains(response, 'itemey 2')
def test_passes_correct_list_to_template(self):
correct_list = List.objects.create()
response = self.client.get(f'/lists/{correct_list.id}/')
self.assertEqual(response.context['list'], correct_list)
class ListAndItemModelsTest(TestCase):
def test_saving_and_retrieving_items(self):
list_ = List()
list_.save()
first_item = Item()
first_item.text = 'The first (ever) list item'
first_item.list = list_
first_item.save()
second_item = Item()
second_item.text = 'Item the second'
second_item.list = list_
second_item.save()
saved_list = List.objects.first()
self.assertEqual(saved_list, list_)
saved_items = Item.objects.all()
self.assertEqual(saved_items.count(), 2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEqual(first_saved_item.text, 'The first (ever) list item')
self.assertEqual(first_saved_item.list, list_)
self.assertEqual(second_saved_item.text, 'Item the second')
self.assertEqual(second_saved_item.list, list_)
class NewListTest(TestCase):
def test_can_save_a_POST_request(self):
self.client.post('lists/new', {'item_text': 'A new list item'})
new_item = Item.objects.first()
self.assertEqual(Item.objects.count(), 1)
self.assertEqual(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/lists/new', data={'item_text': 'A new list item'})
new_list = List.objects.first()
self.assertRedirects(response, f'/lists/{new_list.id}/')
class NewItemTest(TestCase):
def test_can_save_a_POST_request_to_an_existing_list(self):
correct_list = List.objects.create()
self.client.post(
f'/lists/{correct_list.id}/add_item',
data={'item_text': 'A new item for an existing list'}
)
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new item for an existing list')
self.assertEqual(new_item.list, correct_list)
def test_redirects_to_list_view(self):
correct_list = List.objects.create()
response = self.client.post(
f'/lists/{correct_list.id}/add_item',
data={'item_text': 'A new item for an existing list'}
)
self.assertRedirects(response, f'/lists/{correct_list.id}/')
VIEWS.PY
from django.shortcuts import redirect, render
# from django.http import HttpResponse
from lists.models import Item, List
def home_page(request):
if request.method == 'POST':
Item.objects.create(text=request.POST['item_text'])
return redirect('/')
items = Item.objects.all()
return render(request, 'home.html')
def view_list(request, list_id):
list_ = List.objects.get()
return render(request, 'list.html', {'list': list_})
def new_list(request):
list_ = List.objects.create()
Item.objects.create(text=request.POST['item_text'], list=list_)
return redirect(f'/lists/{list.id}/')
def add_item(request, list_id):
list_ = List.objects.get(id=list_id)
Item.objects.create(text=request.POST['item_text'], list=list_)
return redirect(f'/lists/{list_.id}/')
SUPERLIST - URLS.PY
from django.urls import path, re_path, include
from lists import views as list_views
from lists import urls as list_urls
urlpatterns = [
#path('admin/', admin.site.urls),
re_path('^$', list_views.home_page, name="home"),
path('lists/', include(list_urls)),
re_path('^lists/new/$', list_views.new_list, name="new_list"),
re_path('^lists/(\d+)/$', list_views.view_list, name="view_list"),
re_path('^lists/(\d+)/add_item$', list_views.add_item, name="add_item"),
]
СПИСОК - URLS.PY
#from django.contrib import admin
from django.urls import path, re_path
from lists import views
urlpatterns = [
#path('admin/', admin.site.urls),
re_path('^new/$', views.new_list, name="new_list"),
re_path('^(\d+)/$', views.view_list, name="view_list"),
re_path('^(\d+)/add_item$', views.add_item, name="add_item"),
]
home.html
<html>
<head>
<title>To-Do lists</title>
</head>
<body>
<h1>Your To-Do list</h1>
<form method="POST" action="/lists/new">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
{% csrf_token %}
</form>
</body>
</html>
list.html
{% extends 'home.html' %}
<body>
<h1>Start a new To-Do list</h1>
<form method="POST" action="/lists/{{ list.id }}/add_item">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
{% csrf_token %}
</form>
<table id="id_list_table">
{% for item in list.item_set.all %}
<tr><td>{{ forloop.counter }}: {{ item.text }}</td></tr>
{% endfor %}
</table>
</body>
Я пытаюсь сохранить пользовательский ввод и убедиться, что страницы перенаправляются правильно, но пока не достигли большого успеха.