Javascript Django+;JS:Can';t跟踪喜欢的帖子。错误请求400
小背景:我正在youtube上的教程中创建类似twitter的应用程序。所以,我是django的初学者,只知道JS的语法 几天前,我遇到了这样一个问题:类似的帖子不算在内。我认为问题在于序列化程序或我的环境(django 2.2;python 3.8.5;使用VS代码) 我的操作处理视图:Javascript Django+;JS:Can';t跟踪喜欢的帖子。错误请求400,javascript,python,django,django-rest-framework,django-serializer,Javascript,Python,Django,Django Rest Framework,Django Serializer,小背景:我正在youtube上的教程中创建类似twitter的应用程序。所以,我是django的初学者,只知道JS的语法 几天前,我遇到了这样一个问题:类似的帖子不算在内。我认为问题在于序列化程序或我的环境(django 2.2;python 3.8.5;使用VS代码) 我的操作处理视图: import random from django.conf import settings from django.http import HttpResponse, Http404, JsonRespon
import random
from django.conf import settings
from django.http import HttpResponse, Http404, JsonResponse
from django.shortcuts import render, redirect
from django.utils.http import is_safe_url
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .forms import TweetForm
from .models import Tweet
from .serializers import TweetSerializer, TweetActionSerializer
ALLOWED_HOSTS = settings.ALLOWED_HOSTS
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def tweet_action_view(request, *args, **kwargs):
'''
id is required.
Action options are: like, unlike, retweet
'''
serializer = TweetActionSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
data = serializer.validated_data
tweet_id = data.get("id")
action = data.get("action")
content = data.get('content')
qs = Tweet.objects.filter(id=tweet_id)
if not qs.exists():
return Response({}, status=404)
obj = qs.first()
if action == "like":
obj.likes.add(request.user)
serializer = TweetSerializer(obj)
return Response(serializer.data, status=200)
elif action == "unlike":
obj.likes.remove(request.user)
elif action == "retweet":
new_tweet = Tweet.objects.create(
user=request.user,
parent=obj,
content = content)
serializer = TweetSerializer(new_tweet)
return Response(serializer.data, status=200)
return Response({}, status=200)
serializers.py:
from django.conf import settings
from rest_framework import serializers
from .models import Tweet
MAX_TWEET_CHAR = settings.MAX_TWEET_CHAR
TWEET_ACTION_OPTIONS = settings.TWEET_ACTION_OPTIONS
class TweetActionSerializer(serializers.Serializer):
id = serializers.IntegerField()
action = serializers.CharField()
content = serializers.CharField(allow_blank = True, required = False)
def validate_action(self, value):
value = value.lower().strip()
if not value in TWEET_ACTION_OPTIONS:
raise serializers.ValidationError('This is not a valid action')
return value
class TweetSerializer(serializers.ModelSerializer):
likes = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Tweet
fields = ['id', 'content', 'likes']
def get_likes(self, obj):
return obj.likes.count()
def validate_content(self, value):
if len(value) > MAX_TWEET_CHAR:
raise serializers.ValidationError("You exceeded maximum number of characters (240)")
return value
home.html:
{% block content %}
<script>
function tweetActionBtn(tweet_id, currentCount) {
console.log(tweet_id, currentCount)
const url = 'api/tweet/action'
const method = 'POST'
const data = JSON.stringify({
id: tweet_id,
action: 'like'
})
const xhr = new XMLHttpRequest()
const csrftoken = getCookie('csrftoken');
xhr.open(method, url)
xhr.setRequestHeader("Content-Type", "application/json")
xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest")
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
xhr.setRequestHeader("X-CSRFToken", csrftoken)
xhr.onload = function() {
loadTweets(tweetsContainerElement)
}
console.log(xhr)
xhr.send()
return
}
function UnlikeBtn(tweet) {
return "<button class='btn btn-outline-primary btn-sm' onclick=tweetActionBtn(" +
tweet.id + "," + tweet.likes + ",'unlike')>Unlike</button>"
}
function RetweetBtn(tweet) {
return "<button class='btn btn-outline-success btn-sm' onclick=tweetActionBtn(" +
tweet.id + "," + tweet.likes + ",'unlike')>Retweet</button>"
}
function LikeBtn(tweet) {
return "<button class='btn btn-primary btn-sm' onclick=tweetActionBtn(" +
tweet.id + "," + tweet.likes + ",'like')>" + tweet.likes + " Likes</button>"
}
function formatTweets(tweet) {
var formattedTweet = "<div class='col-12 col-md-10 mx-auto border rounded py-3 mb-4 tweet' id='tweet-" + tweet.id + "'><p>" + tweet.content +
"</p><div class='btn-group'>" +
LikeBtn(tweet) +
UnlikeBtn(tweet) +
RetweetBtn(tweet) +
"</div></div>"
return formattedTweet
}
</script>
{% endblock content %}
服务器向我发送以下消息:
XMLHttpRequest { onreadystatechange: null, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "", status: 0, statusText: "", responseType: "", response: "" }
400 Bad request.
Bad Request: /api/tweet/action
[09/Jan/2021 16:43:11] "POST /api/tweet/action HTTP/1.1" 400 71
我去了/api/tweet/action
,试图发布一些东西,得到了以下结果:
HTTP 400 Bad Request
Allow: OPTIONS, POST
Content-Type: application/json
Vary: Accept
{
"detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)"
}
下一步可以尝试什么?如果未发送预期数据或数据格式错误,则会出现该错误 建模数据的方式决定了post请求是否需要一些数据。如果在您的模型中,某个字段被标记为
required=true
,那么它应该在您的post请求中可用。在您的情况下,它可能是操作字段。因此,您需要在post请求中发送此数据
如果使用浏览器中的开发者控制台查看post请求,您将看到post请求中没有正文
因此,您应该使用xhr.send(data)
而不是xhr.send()
此外,您不需要为tweet操作创建id字段,Django可以自动处理该操作。默认情况下,Django向每个模型添加一个id字段,该字段用作该模型的主键
让客户端能够发送id是个坏主意,应该在服务器中生成id,即post请求不应该为要在后端创建的数据设置
id
字段。xhr.send(data)
而不是xhr.send()
。您正在执行一个post请求,该请求需要一些数据。建议您只显示重新创建问题所需的代码,而不要发布所有内容,因为这会降低您的问题得到回答的机会。请阅读
HTTP 400 Bad Request
Allow: OPTIONS, POST
Content-Type: application/json
Vary: Accept
{
"detail": "JSON parse error - Expecting value: line 1 column 1 (char 0)"
}