Я следую за серией https://youtu.be/f1R_bykXHGE, и я получаю сообщение об ошибке с кодом для сериализаторов. Код работает нормально, но когда я попытался добавить Like = сериализаторы .SerializerMethodField (read_only = True) выдает ошибку AttributeError: объект «TweetSerializer» не имеет атрибута «get_likes». Я не могу найти ошибку.
serializers.py
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_LENGTH:
raise forms.ValidationError("This tweet is too long")
return value
# models.py
import random
from django.conf import settings
from django.db import models
User = settings.AUTH_USER_MODEL
# Create your models here.
class TweetLike(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
tweet = models.ForeignKey("Tweet", on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
class Tweet(models.Model):
# id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE) #many users can have maany tweets
likes = models.ManyToManyField(User, related_name='tweet_user', blank=True, through=TweetLike)
content = models.TextField(null=True, blank=True)
image = models.FileField(upload_to='images/', blank=True, null=True) #image bs file
timestamp = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.content
class Meta:
ordering = ['-id']
def serialize(self):
return {
"id": self.id,
"content": self.content,
"likes": random.randint(0, 25)
}
views.py
import random
from django.conf import settings
from django.http import HttpResponse, Http404, JsonResponse
from django.shortcuts import render, redirect
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.permissions import IsAuthenticated
#safe urls
from django.utils.http import is_safe_url
from .forms import TweetForm
from .models import Tweet
from .serializers import TweetSerializer, TweetActionSerializer
@api_view(['GET'])
def tweet_list_view(request, *args, **kwargs):
qs = Tweet.objects.all()
serializer = TweetSerializer(qs, many=True)
print(serializer.data)
return Response(serializer.data, status=200)
Пожалуйста, помогите мне в этом. Спасибо
**Here is the error log**
[09/May/2020 07:36:47] "GET / HTTP/1.1" 200 8172
Internal Server Error: /tweets
Traceback (most recent call last):
File "/home/Aps/dev/env/lib64/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
raise exc
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/decorators.py", line 50, in handler
return func(*args, **kwargs)
File "/home/Aps/dev/tweeting/tweets/views.py", line 99, in tweet_list_view
print(serializer.data)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/serializers.py", line 760, in data
ret = super().data
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/serializers.py", line 260, in data
self._data = self.to_representation(self.instance)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/serializers.py", line 677, in to_representation
return [
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/serializers.py", line 678, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/serializers.py", line 529, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/home/Aps/dev/env/lib64/python3.8/site-packages/rest_framework/fields.py", line 1904, in to_representation
method = getattr(self.parent, self.method_name)
AttributeError: 'TweetSerializer' object has no attribute 'get_likes'
[09/May/2020 07:36:47] "GET /tweets HTTP/1.1" 500 20511
Frontend, куда я пытаюсь загрузить все твиты.
{% extends 'base.html' %}
{% block head_title %}
this is going to be an amazing.
{% endblock head_title %}
{% block content%}
<div class='row text-center'>
<div class='col'>
<h2>Welcome to tweetme2</h2>
</div>
</div>
<div class='row mb-3'>
<div class='col-md-4 mx-auto col-10'>
<form class='form' id='tweet-create-form' method='POST' action='/create-tweet'>
{% csrf_token %}
<div class='d-none alert alert-danger' id='tweet-create-form-error'></div>
<input type='hidden' value='/' name='next' />
<textarea required='required' class='form-control' name='content' placeholder='Your tweet...'></textarea>
<button type='submit' class='btn btn-primary mt-2'>Tweet</button>
</form>
</div>
</div>
<div class='row' id='tweets'>
Loading...
</div>
<script>
function handleTweetFormError(msg, display){
var myErrorDiv = document.getElementById("tweet-create-form-error")
if (display === true){
// show error
myErrorDiv.setAttribute("class", "d-block alert alert-danger")
myErrorDiv.innerText = msg
}else{
//hide error
myErrorDiv.setAttribute("class", "d-none alert alert-danger")
}
}
function handleTweetCreateFormDidSumbit(event){
event.preventDefault()
const myForm = event.target
const myFormData = new FormData(myForm)
const url = myForm.getAttribute("action")
const method = myForm.getAttribute("method")
const xhr = new XMLHttpRequest()
const responseType = "json"
xhr.responseType = responseType
xhr.open(method, url)
//https://docs.djangoproject.com/en/3.0/ref/request-response/
xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest")
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
xhr.onload = function(){
if (xhr.status === 201){
handleTweetFormError("", false)
//const serverResponse = xhr.response
const newTweetJson = xhr.response
//const newTweetJson = JSON.parse(newTweet)
//console.log(newTweetJson.likes)
//console.log(xhr.status, serverResponse)
const newTweetElement = formatTweetElement(newTweetJson)
//console.log(newTweetElement)
//const tweetsEl = document.getElementById("tweets")
//loadTweets(tweetsEl)
const ogHtml = tweetsContainerElement.innerHTML
tweetsContainerElement.innerHTML = newTweetElement + ogHtml
myForm.reset()
} else if (xhr.status === 400){
const errorJson = xhr.response
//console.log(errorJson)
const contentError = errorJson.content
let contentErrorMsg;
if (contentError){
contentErrorMsg = contentError[0]
if (contentErrorMsg){
handleTweetFormError(contentErrorMsg, true)
}else{
alert("An error occured, please try again.")
}
} else {
alert("An error occured, please try again.")
}
//console.log(contentErrorMsg)
}else if (xhr.status === 401){
alert("You must login!")
window.location.href = "/login"
}
else if (xhr.status === 403){
alert("You must login!")
window.location.href = "/login"
}
else if (xhr.status === 500){
alert("There was a server error, please try again.")
}
}
xhr.onerror = function(){
alert("An error occured. Please try again later.")
}
xhr.send(myFormData)
//console.log(url, method)
//for (var myIteam of myFormData.entries()){
//console.log(myIteam)
//}
//console.log(event)
}
const tweetCreateFormEl = document.getElementById("tweet-create-form")
tweetCreateFormEl.addEventListener("submit", handleTweetCreateFormDidSumbit)
//const tweetsEl = document.getElementById("tweets")
const tweetsContainerElement = document.getElementById("tweets")
function loadTweets(tweetsElement) {
const xhr = new XMLHttpRequest()
const method = 'GET' // "POST"
const url = "/tweets"
const responseType = "json"
xhr.responseType = responseType
xhr.open(method, url)
xhr.onload = function() {
const serverResponse = xhr.response
const listedItems = serverResponse // array
var finalTweetStr = ""
var i;
for (i=0;i<listedItems.length; i++) {
var tweetObj = listedItems[i]
var currentItem = formatTweetElement(tweetObj)
finalTweetStr += currentItem
}
tweetsElement.innerHTML = finalTweetStr
}
xhr.send()
}
//loadTweets(tweetsEl)
loadTweets(tweetsContainerElement)
function handleDidLike(tweet_id, currentCount){
console.log(tweet_id, currentCount)
currentCount++
return
}
function LikeBtn(tweet) {
return "<button class='btn btn-primary btn-sm' onclick=handleDidLike(" +
tweet.id + "," + tweet.likes + ",'like')>" + tweet.likes + " Likes</button>"
}
function formatTweetElement(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) +
"</div></div>"
return formattedTweet
}
</script>
{% endblock content %}