AttributeError: объект 'TweetSerializer' не имеет атрибута 'get_likes' - PullRequest
0 голосов
/ 09 мая 2020

Я следую за серией 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 %}

1 Ответ

0 голосов
/ 09 мая 2020

В вашем TweetSerializer serializerMethods должен быть за пределами class Meta и внутри TweetSerializer, как это

class TweetSerializer(serializers.ModelSerializer):
    likes = serializers.SerializerMethodField(read_only=True)

    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

    class Meta:
        model = Tweet
        fields = ['id', 'content','likes']
...