teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

590閲覧

Djangoで'AnonymousUser' object is not iterableエラーを解決したい

Mr_PONPON_MARU

総合スコア35

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/06/27 01:33

編集2023/06/27 01:59

0

0

実現したいこと

会員登録制の記事投稿アプリをDjangoで開発しています。
イイね機能を実装した記事詳細ページに非ログインユーザーがアクセスすると、AnonymousUser' object is not iterableエラーが発生してしまいます。

前提

記事詳細ページはログイン済ユーザーと非ログインユーザーどちらもアクセスできるようにしてあり、イイね機能の要件は下記で考えています。

  • 非ログインユーザがアクセスしている場合はイイねの総数だけ見ることができるがイイねの追加はできない
  • ログイン済ユーザーが既にイイねを押した状態と、まだイイねを押していない状態でテンプレート表示を切り替える
  • 既にイイねを押した状態でもう一度イイねを押すと、そのイイねが取り消される
  • イイねの追加/削除の処理はAjaxを用いた非同期通信で行う

該当のソースコード

記事に対するイイねはLikeForArticleモデルで定義した。

models.py

1class CustomUser(AbstractUser): 2 3 username = models.CharField( 4 _("username"), 5 max_length=30, 6 help_text='Required 30 characters or fewer.', 7 unique=True, 8 error_messages={ 9 'unique': _("This Username already exists."), 10 },) 11 12 email = models.EmailField( 13 _('email'), 14 unique=True, 15 error_messages={ 16 'unique': _("A user with that email address already exists."), 17 },) 18 19 class Meta: 20 verbose_name_plural = 'CustomUser' 21 22 23class Article(models.Model): 24 25 post_user = models.ForeignKey(CustomUser, verbose_name='Post User', on_delete=models.CASCADE, related_name='name',) 26 title = models.CharField(verbose_name='title', max_length=50,) 27 content = MDTextField() 28 created_at = models.DateField(verbose_name='created_at', auto_now_add=True,) 29 30 class Meta: 31 verbose_name_plural = 'Article' 32 33 def __str__(self): 34 return self.title 35 36 37class LikeForArticle(models.Model): 38 target = models.ForeignKey(Article, on_delete=models.CASCADE,) 39 user = models.ForeignKey(CustomUser, on_delete=models.CASCADE,) 40 timestamp = models.DateTimeField(default=timezone.now,)

views.py

1from django.shortcuts import render, get_object_or_404 2from django.views import generic 3from django.http import JsonResponse 4from .models import Article, LikeForArticle 5 6class ArticleDetailView(generic.DetailView): 7 model = Article 8 template_name = 'article_detail.html' 9 10 def get_context_data(self, **kwargs): #ユーザが既にイイねしているかどうかの判断 11 context = super().get_context_data(**kwargs) 12 13 like_for_article_count = self.object.likeforarticle_set.count() 14 #記事に対するイイね数 15 context['like_for_article_count'] = like_for_article_count 16 17 #ユーザがイイねしているかどうか 18 if self.object.likeforarticle_set.filter(user=self.request.user).exists(): 19 context['is_user_liked_for_article'] = True 20 else: 21 context['is_user_liked_for_article'] = False 22 23 return context 24 25#記事に対するイイねの非同期処理 26def like_for_article(request): 27 article_pk = request.POST.get('article_pk') 28 context = { 29 'user': request.user, 30 } 31 article = get_object_or_404(Article, pk=article_pk) 32 like = LikeForArticle.objects.filter(target=article, user=request.user) 33 34 #既にイイねしていたら削除、していなかったらイイね 35 if like.exists(): 36 like.delete() 37 context['method'] = 'delete' 38 else: 39 like.create(target=article, user=request.user) 40 context['method'] = 'create' 41 42 context['like_for_article_count'] = article.likeforarticle_set.count() 43 44 return JsonResponse(context)

urls.py

1app_name = 'article' 2 3urlpatterns = [ 4 path('article_detail/<int:pk>', views.ArticleDetailView.as_view(), name='article_detail'), 5 path('like_for_article/', views.like_for_article, name='like_for_article'), #追加 6]

article_detail.html

1{% block background %} 2 <div class="text-center"> 3 <h1 class="display-sm-4 display-lg-3">{{ object.title }}</h1> 4 <p class="h6 text-uppercase u-letter-spacing-sm mb-2">by {{ object.post_user }}</p> 5 <p class="h6 text-uppercase u-letter-spacing-sm mb-2">{{ object.view_count }} view</p> 6 <p class="h6 text-uppercase u-letter-spacing-sm mb-2">Posted:{{ object.created_at }} | {% if object.updated_at %}Updated:{{ object.updated_at }}{% endif %}</p> 7 8 9 {% if is_user_liked_for_article %} 10 <button type="button" id="ajax-like-for-post" style="border:none;background:none"> 11 <!-- すでにイイねしている時はfasクラス --> 12 <i class="fas fa-heart text-danger" id="like-for-post-icon"></i> 13 </button> 14 {% else %} 15 <button type="button" id="ajax-like-for-post" style="border:none;background:none"> 16 <!-- イイねしていないときはfarクラス --> 17 <i class="far fa-heart text-danger" id="like-for-post-icon"></i> 18 </button> 19 {% endif %} 20 <!-- イイねの数 --> 21 <span id="like-for-post-count">{{ like_for_article_count }}</span> 22 <span>Likes</span> 23 24</div> 25{% endblock %} 26{% block js %} 27<script type="text/javascript"> 28 /* ポストに対するイイね */ 29 document.getElementById('ajax-like-for-post').addEventListener('click', e => { 30 e.preventDefault(); 31 const url = '{% url "article:like_for_article" %}'; 32 fetch(url, { 33 method: 'POST', 34 body: `article_pk={{article.pk}}`, 35 headers: { 36 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 37 'X-CSRFToken': '{{ csrf_token }}', 38 }, 39 }).then(response => { 40 return response.json(); 41 }).then(response => { 42 // イイね数を書き換える 43 const counter = document.getElementById('like-for-post-count') 44 counter.textContent = response.like_for_article_count 45 const icon = document.getElementById('like-for-post-icon') 46 // 作成した場合はハートを塗る 47 if (response.method == 'create') { 48 icon.classList.remove('far') 49 icon.classList.add('fas') 50 icon.id = 'like-for-post-icon' 51 } else { 52 icon.classList.remove('fas') 53 icon.classList.add('far') 54 icon.id = 'like-for-post-icon' 55 } 56 }).catch(error => { 57 console.log(error); 58 }); 59 }); 60</script> 61{% endblock %}

発生している問題・エラーメッセージ

非ログインユーザーが記事詳細ページにアクセスすると、AnonymousUser' object is not iterableエラーが発生します。

TypeError at /article_detail/10 'AnonymousUser' object is not iterable Request Method: GET Request URL: http://127.0.0.1:8000/article_detail/10 Django Version: 3.0.3 Exception Type: TypeError Exception Value: 'AnonymousUser' object is not iterable Exception Location: /Users/xxx/anaconda3/envs/venv_prototyping/lib/python3.7/site-packages/django/utils/functional.py in inner, line 225 Python Executable: /Users/xxx/anaconda3/envs/venv_prototyping/bin/python Python Version: 3.7.6

試したこと

ログイン済ユーザーでアクセスした場合は、エラーが起きず正常に作動しました。また、views.pyArticleDetailViewクラスのget_context_dataメソッド内で、self.request.userAnonymousUserの場合にis_user_liked_for_articleFalseに設定しましたが、エラーが解決しませんでした。

どのように修正すればエラーが解決し、非ログインユーザーが記事詳細ページにアクセスできるようになりますか?

views.py

1class ArticleDetailView(generic.DetailView): 2 model = Article 3 template_name = 'article_detail.html' 4 5 def get(self, request, *args, **kwargs): #閲覧数のカウント処理 6 self.object = self.get_object() 7 self.object.view_count += 1 8 self.object.save() 9 context = self.get_context_data(object=self.object) 10 return self.render_to_response(context) 11 12 def get_context_data(self, **kwargs): #ユーザが既にイイねしているかどうかの判断 13 context = super().get_context_data(**kwargs) 14 15 like_for_article_count = self.object.likeforarticle_set.count() 16 #記事に対するイイね数 17 context['like_for_article_count'] = like_for_article_count 18 19 #非ログインユーザーの場合 20 if self.request.user.id is None: 21 context['is_user_liked_for_article'] = False 22 23 #ログインユーザがイイねしているかどうか 24 if self.object.likeforarticle_set.filter(user=self.request.user).exists(): 25 context['is_user_liked_for_article'] = True 26 else: 27 context['is_user_liked_for_article'] = False 28 29 return context

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

get_context_dataメソッドを下記のように書き換えることで解決ができました。
調べてみると、AnonymousUserはユーザーモデルのインスタンスとして扱えないことに注意する必要があると分かりました。その上で、問題となっている点はfilter(user=self.request.user)としている点です。AnonymousUserである場合、ここの処理がうまくできないので、ちゃんと条件分岐してあげる必要がありました。

views.py

1def get_context_data(self, **kwargs): #ユーザが既にイイねしているかどうかの判断 2 context = super().get_context_data(**kwargs) 3 4 like_for_article_count = self.object.likeforarticle_set.count() 5 #記事に対するイイね数 6 context['like_for_article_count'] = like_for_article_count 7 8 #非ログインユーザーの場合 9 if self.request.user.id is None: 10 context['is_user_liked_for_article'] = False 11 #ログインユーザがイイねしているかどうか 12 elif self.object.likeforarticle_set.filter(user=self.request.user).exists(): 13 context['is_user_liked_for_article'] = True 14 else: 15 context['is_user_liked_for_article'] = False 16 17 return context

投稿2023/06/27 02:23

Mr_PONPON_MARU

総合スコア35

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

この回答はGPT-4による自動生成回答です

unter.textContent = response.like_for_article_count;

// イイねアイコンを切り替える const icon = document.getElementById('like-for-post-icon'); if (response.method === 'create') { icon.classList.remove('far'); icon.classList.add('fas'); } else { icon.classList.remove('fas'); icon.classList.add('far'); } });

});
</script>
{% endblock %}

### エラー内容 非ログインユーザーが記事詳細ページにアクセスすると、`AnonymousUser' object is not iterable`エラーが発生します。 ### 試したこと `views.py`の`ArticleDetailView`クラスの`get_context_data`メソッド内で、`self.request.user`が`AnonymousUser`の場合に`is_user_liked_for_article`を`False`に設定しましたが、エラーが解決しませんでした。 どのように修正すればエラーが解決し、非ログインユーザーが記事詳細ページにアクセスできるようになりますか?

投稿2023/06/27 01:34

teratail-ai

Powered by GPT-4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Mr_PONPON_MARU

2023/06/27 01:49

get_context_dataメソッド内にリクエストユーザーがAnonymousUserだった場合の処理を追記し、テンプレートでも同様の条件分岐を設けましたが、エラーが解決しませんでした。 ```views.py def get_context_data(self, **kwargs): #ユーザが既にイイねしているかどうかの判断 context = super().get_context_data(**kwargs) like_for_article_count = self.object.likeforarticle_set.count() #記事に対するイイね数 context['like_for_article_count'] = like_for_article_count #非ログインユーザーの場合 if self.request.user.id is None: context['is_user_liked_for_article'] = False #ログインユーザがイイねしているかどうか if self.object.likeforarticle_set.filter(user=self.request.user).exists(): context['is_user_liked_for_article'] = True else: context['is_user_liked_for_article'] = False return context ``` ```article_detail.html {% if user.id is not None %} {% if is_user_liked_for_article %} <button type="button" id="ajax-like-for-post" style="border:none;background:none"> <!-- すでにイイねしている時はfasクラス --> <i class="fas fa-heart text-danger" id="like-for-post-icon"></i> </button> {% else %} <button type="button" id="ajax-like-for-post" style="border:none;background:none"> <!-- イイねしていないときはfarクラス --> <i class="far fa-heart text-danger" id="like-for-post-icon"></i> </button> {% endif %} {% endif %} <!-- イイねの数 --> <span id="like-for-post-count">{{ like_for_article_count }}</span> <span>Likes</span> ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問