TypeError: ‘NoneType’ object is not iterable
when testing a site using pytest, I get an error in the test, and I can’t figure out what is causing the error, please tell me where exactly the problem is in my code, and how to fix it (Files with tests cannot be changed - pytest). My code views.py:
from django.views.generic import (
CreateView, DeleteView, DetailView, ListView, UpdateView
)
from django.shortcuts import get_object_or_404, redirect, render
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.contrib.auth.forms import PasswordChangeForm
from django.urls import reverse_lazy
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.mixins import UserPassesTestMixin
from blog.models import Category, Post
from .models import Comment
from .forms import CommentForm
from .forms import PostForm
from .forms import UserProfileForm
User = get_user_model()
class OnlyAuthorMixin(UserPassesTestMixin):
def test_func(self):
object = self.get_object()
return object.author == self.request.user
class PostListView(ListView):
model = Post
queryset = (
Post.published
.order_by('-pub_date')
)
paginate_by = 10
template_name = 'blog/index.html'
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
form_class = PostForm
template_name = 'blog/create.html'
def get_success_url(self):
return reverse_lazy(
'blog:profile',
kwargs={'username': self.request.user.username}
)
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostDetailView(DetailView):
model = Post
template_name = 'blog/detail.html'
context_object_name = 'post'
def get_object(self, queryset=None):
post_id = self.kwargs.get("post_id")
return get_object_or_404(Post, pk=post_id)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if context is None:
context = {}
context['form'] = CommentForm()
if self.object:
context['comments'] = self.object.comments.select_related('author')
context['comments_count'] = self.object.comments.count()
else:
context['comments'] = []
context['comments_count'] = 0
return context
@login_required
def add_comment(request, post_id):
post = get_object_or_404(Post, pk=post_id)
form = CommentForm(request.POST)
if form.is_valid():
print("Form is valid")
comment = form.save(commit=False)
comment.author = request.user
comment.post = post
comment.save()
return redirect('blog:post_detail', post_id=post_id)
return render(request, 'blog/detail.html', {
'form': form,
'post': post,
'comments': post.comments.select_related('author'),
'comments_count': post.comments.count()
})
@login_required
def edit_comment(request, post_id, comment_id):
comment = get_object_or_404(Comment, id=comment_id)
if comment.author != request.user:
return redirect('blog:post_detail', post_id=post_id)
if request.method == 'POST':
form = CommentForm(request.POST, instance=comment)
if form.is_valid():
form.save()
return redirect('blog:post_detail', post_id=post_id)
else:
form = CommentForm(instance=comment)
return render(
request, 'blog/comment.html',
{'form': form, 'comment': comment}
)
@login_required
def delete_comment(request, post_id, comment_id):
comment = get_object_or_404(Comment, id=comment_id)
if comment.author != request.user and not request.user.is_superuser:
return redirect('blog:post_detail', post_id=post_id)
if request.method == 'POST':
comment.delete()
return redirect('blog:post_detail', post_id=post_id)
return render(request, 'blog/comment.html', {'comment': comment})
@login_required
def edit_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('blog:profile', username=request.user.username)
else:
form = UserProfileForm(instance=request.user)
return render(request, 'blog/edit_profile.html', {'form': form})
@login_required
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user)
return redirect('blog:profile', username=request.user.username)
else:
form = PasswordChangeForm(request.user)
return render(request, 'blog/password_change_done.html', {'form': form})
class PostUpdateView(LoginRequiredMixin, OnlyAuthorMixin, UpdateView):
model = Post
form_class = PostForm
template_name = 'blog/create.html'
def get_success_url(self):
return reverse_lazy(
'blog:post_detail',
kwargs={'post_id': self.object.pk}
)
def get_object(self, queryset=None):
post_id = self.kwargs.get('post_id')
return get_object_or_404(Post, pk=post_id)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if context is None:
context = {}
return context
def dispatch(self, request, *args, **kwargs):
return redirect('blog:post_detail', post_id=self.kwargs.get('post_id'))
class PostDeleteView(LoginRequiredMixin, OnlyAuthorMixin, DeleteView):
model = Post
template_name = 'blog/create.html'
success_url = reverse_lazy('blog:index')
def get_object(self, queryset=None):
post_id = self.kwargs.get('post_id')
return get_object_or_404(Post, pk=post_id)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if context is None:
context = {}
return context
class CategoryPostsView(ListView):
model = Category
template_name = 'blog/category.html'
context_object_name = 'page_obj'
paginate_by = 10
def get_queryset(self):
category_slug = self.kwargs.get('category_slug')
category = get_object_or_404(
Category,
slug=category_slug,
is_published=True
)
return category.posts(manager='published').order_by('-pub_date')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if context is None:
context = {}
category_slug = self.kwargs.get('category_slug')
category = get_object_or_404(
Category,
slug=category_slug,
is_published=True
)
context['category'] = category
return context
class ProfileView(DetailView):
model = User
template_name = 'blog/profile.html'
context_object_name = 'profile'
def get_object(self):
username = self.kwargs.get("username")
return get_object_or_404(User, username=username)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if context is None:
context = {}
user = self.get_object()
posts = Post.objects.filter(author=user).order_by('-pub_date')
paginator = Paginator(posts, 10)
page_number = self.request.GET.get('page')
page_obj = paginator.get_page(page_number)
context['page_obj'] = page_obj
return context
Error when running pytest:
============================================================================ FAILURES ============================================================================ ___________________________________________________________________________ test_post ____________________________________________________________________________
published_category = <Category: Break Star Clear Responsibility Once Rest>, published_location = <Location: Bianca Roach DVM>
user_client = <django.test.client.Client object at 0x000002DF6F6B7E60>, another_user_client = <django.test.client.Client object at 0x000002DF6F798980>
unlogged_client = <django.test.client.Client object at 0x000002DF6F79A690>
comment_to_a_post = <Comment: Comment by deannawillis on Serve Moment Small Those Note Difficult>
create_post_context_form_item = KeyVal(key='form', val=<PostForm bound=False, valid=False, fields=(title;text;pub_date;location;category;image)>)
PostModel = <class 'blog.models.Post'>, CommentModelAdapter = <class 'adapters.comment.CommentModelAdapter.<locals>._CommentModelAdapter'>
main_content_tester = <test_content.MainPostContentTester object at 0x000002DF6F7A0CE0>
@pytest.mark.django_db(transaction=True)
def test_post(
published_category: Model,
published_location: Model,
user_client: django.test.Client,
another_user_client: django.test.Client,
unlogged_client: django.test.Client,
comment_to_a_post: Model,
create_post_context_form_item: Tuple[str, BaseForm],
PostModel: Type[Model],
CommentModelAdapter: CommentModelAdapterT,
main_content_tester: MainPostContentTester
):
_, ctx_form = create_post_context_form_item
create_a_post_get_response = get_create_a_post_get_response_safely(
user_client
)
response_on_created, created_items = _test_create_items(
PostModel,
PostModelAdapter,
another_user_client,
create_a_post_get_response,
ctx_form,
published_category,
published_location,
unlogged_client,
user_client,
)
# checking images are visible on post creation
created_content = response_on_created.content.decode('utf-8')
img_count = created_content.count('<img')
expected_img_count = main_content_tester.n_or_page_size(len(created_items))
assert img_count >= expected_img_count, (
'Убедитесь, что при создании публикации она отображается с картинкой.'
)
> edit_response, edit_url, del_url = _test_edit_post(
CommentModelAdapter,
another_user_client,
comment_to_a_post,
unlogged_client=unlogged_client,
user_client=user_client,
)
tests\test_post.py:111:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests\test_post.py:360: in _test_edit_post
edit_response = _test_edit(
tests\test_edit.py:46: in _test_edit
updated_form = create_updated_form(**update_props)
tests\test_edit.py:35: in create_updated_form
_, form = _testget_context_item_by_class(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
context = None, cls = <class 'django.forms.forms.BaseForm'>, err_msg = '', inside_iter = False
def _testget_context_item_by_class(
context, cls: type, err_msg: str, inside_iter: bool = False
) -> KeyVal:
"""If `err_msg` is not empty, empty return value will
produce an AssertionError with the `err_msg` error message"""
def is_a_match(val: Any):
if inside_iter:
try:
return isinstance(iter(val).__next__(), cls)
except Exception:
return False
else:
return isinstance(val, cls)
matched_keyval: KeyVal = KeyVal(key=None, val=None)
matched_keyvals: List[KeyVal] = []
> for key, val in dict(context).items():
E TypeError: 'NoneType' object is not iterable
tests\conftest.py:302: TypeError
I tried to check the value of context for None, if context gets the value None, assigned an empty dictionary in the PostDetailView, PostUpdateVew, ProfileView classes, but as a result I also get an error when running pytest