django初心者です。
いいね機能を追加するためにapiを使ってJavaScriptでAjax通信をしようとした際にクリックしても反応しないエラーが発生しました。
デバッグを見るとjsファイルは読み込まれているようですが、反応していません。
解決していただけると助かります。
エラーメッセージはありませんが、デバッグをfluseにすると500エラーが発生します。
試したこと
・スーパーリロード
・django-static-md5urlを使う
・キャッシュバスティングの設定(500エラーの発生)
ファイル構造
cissapp/
├ciss
| └views.py
├static
| └js
| └vote.js
├template
| └detail.html
views.py
views.py
1class TopicDetailView(FormView): 2 template_name = 'cissapp/detail.html' 3 form_class = TopicCreateForm 4 5 def form_valid(self, form): 6 ctx = {'form': form} 7 if self.request.POST.get('next', '') == 'confirm': 8 return render(self.request, 'topics/confirm_topic.html', ctx) 9 if self.request.POST.get('next', '') == 'back': 10 return render(self.request, 'topics/create_other_topic.html', ctx) 11 if self.request.POST.get('next', '') == 'create': 12 13 form.save_with_data(self.kwargs.get('pk')) 14 return super().form_valid(form) 15 else: 16 return redirect(reverse_lazy('cissapp:index')) 17 18 def get_success_url(self): 19 return reverse_lazy('cissapp:detail', kwargs={'pk': self.kwargs['pk']}) 20 21 def get_context_data(self): 22 ctx = super().get_context_data() 23 print('完了3-1') 24 ctx['data'] = Data.objects.get(id=self.kwargs['pk']) 25 print('完了3-2') 26 #ctx['posts'] = Data.objects.filter(data_id=self.kwargs['pk']).order_by('no') 27 #ctx['posts'] = Topic.objects.filter(data = self.kwargs['pk']).order_by('-created') 28 ctx['posts'] = Topic.objects.filter( 29 data_id=self.kwargs['pk']).annotate(vote_count=Count('vote')).order_by('-created') 30 print('完了3-3') 31 return ctx
models.py
models.py
1class Data(models.Model): 2 category = models.CharField("科目種別", blank=True, max_length=100) 3 no = models.CharField("授業番号", blank=True, max_length=10) 4 semester = models.CharField("学期", blank=True, max_length=5) 5 day = models.CharField("曜日", blank=True, max_length=1) 6 name = models.CharField("科目", blank=True, max_length=20) 7 8 9 def __str__(self): 10 return(self.name) 11 12class Topic(models.Model): 13 id = models.BigAutoField( 14 primary_key=True, 15 ) 16 no = models.IntegerField( 17 default=0, 18 ) 19 data = models.ForeignKey( 20 Data, 21 on_delete=models.PROTECT, 22 ) 23 24 title = models.CharField( 25 'タイトル', 26 max_length=30, 27 null=True, 28 blank=False, 29 ) 30 content = models.TextField( 31 verbose_name='本文', 32 null=True, 33 blank=False, 34 ) 35 author = models.ForeignKey( 36 get_user_model(), on_delete=models.CASCADE, blank=True 37 ) 38 time = models.DateTimeField( 39 default=timezone.now 40 ) 41 created = models.DateTimeField( 42 auto_now_add=True, 43 ) 44 pub_flg = models.BooleanField( 45 default=True, 46 ) 47 48 49 def __str__(self): 50 return '{}-{}'.format(self.data.id, self.no) 51 52class VoteManager(models.Manager): 53 def create_vote(self, ip_address, comment_id): 54 vote = self.model( 55 ip_address=ip_address, 56 comment_id = comment_id 57 ) 58 try: 59 vote.save() 60 except: 61 return False 62 return True 63 64class Vote(models.Model): 65 topic = models.ForeignKey( 66 Topic, 67 on_delete=models.CASCADE, 68 null=True, 69 ) 70 ip_address = models.CharField( 71 'IPアドレス', 72 max_length=50, 73 ) 74 75 objects = VoteManager() 76 77 def __str__(self): 78 return '{}-{}'.format(self.topic.title, self.topic.no)
detail.html
<h4>投稿一覧</h4> <div class="ui segment"> {% if posts %} {% for post in posts %} <div class="ui segment secondary"> <p>投稿日:{{post.created}}<br>タイトル:{{post.title}}</p> <!--いいね機能--> {% if post.pub_flg %} <p>投稿内容:{{post.content | comment_filter | safe}}</p> <div class="ui right aligned vertical segment"> <div class="vote_button" style="cursor: pointer;" data-comment-id="{{post.no}}" data-count="{{post.vote_count}}"> <i class="heart outline icon"></i> <span class="vote_counter"> {% if post.vote_count >= 0 %} {{post.vote_count}} {% endif %} </span> </div> </div> {% else %} <p style="color: grey">コメントは非表示とされました</p> {% endif %} <!--//いいね機能--> </div> {% endfor %} {% else %} <div class="ui warning message"><p>まだコメントはありません</p></div> {% endif %} </div>
setting.py
DEBUG = True ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ 'accounts.apps.AccountsConfig', 'cissapp.apps.CissappConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'topics', 'api', 'debug_toolbar', 'django_static_md5url', ] INTERNAL_IPS = [ '127.0.0.1', ] STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
vote.js
$(function(){ // setup for ajax var csrftoken = getCookie('csrftoken'); $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); var votedList = [];// 連打防止用のコメントID格納リスト // いいねボタン押下時の処理 onClickVoteButton(); function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } function onClickVoteButton() { $('.vote_button').on('click', function() { var commentId = $(this).data('comment-id'); var currentCount = $(this).data('count'); var countViewer = $(this).find('.vote_counter'); if (votedList.indexOf(commentId) < 0) { vote(commentId, currentCount, countViewer); } }); } // ajax通信して投票結果を反映する function vote(commentId, currentCount, countViewer) { let url = '/api/v1/vote/'; $.ajax({ type: 'POST', url: url, data: { comment_id: commentId } }).then( data => { if (data.result) { countViewer.text(currentCount + 1); votedList.push(commentId); } }, error => { if (error.responseJSON.message) { alert(error.responseJSON.message); } } ); } });