python Django rest框架类型错误:“NoneType”对象不可调用

enxuqcxy  于 2023-02-21  发布在  Python
关注(0)|答案(1)|浏览(172)
  • */www.example.commodels.py
class Like(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             related_name='likes',
                             on_delete=models.CASCADE)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

class Content(models.Model):
    """Контент (фильмы, сериалы, и т.д.)"""
    title_ru = models.CharField('Название', max_length=200, blank=True)
    title_en = models.CharField('Название на английском', max_length=200, blank=True)
    rating = models.FloatField('Оценка', validators=[
        MaxValueValidator(10.0),
        MinValueValidator(0.0),
    ], default=0.0)
    year = models.PositiveSmallIntegerField('Дата выхода', default=date.today().year, null=True)
    kinopoisk_id = models.IntegerField('Кинопоиск id')
    is_banned = models.BooleanField('Бан', default=False)

    def __str__(self):
        return f'{self.title_ru} / {self.title_en}'

    class Meta:
        ordering = ['-year']
        verbose_name = 'Контент'
        verbose_name_plural = 'Контент'
  • */www.example.comservices.py
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType

User = get_user_model()

def add_like(obj, user):
    """Лайк пользователя"""
    obj_type = ContentType.objects.get_for_model(obj)
    like, is_created = Like.objects.get_or_create(
        content_type=obj_type, object_id=obj.id, user=user)
    return like

def remove_like(obj, user):
    """Лайкает `obj`."""
    obj_type = ContentType.objects.get_for_model(obj)
    Like.objects.filter(
        content_type=obj_type, object_id=obj.id, user=user
    ).delete()

def is_fan(obj, user) -> bool:
    """Удаляет лайк с `obj`."""
    if not user.is_authenticated:
        return False
    obj_type = ContentType.objects.get_for_model(obj)
    likes = Like.objects.filter(
        content_type=obj_type, object_id=obj.id, user=user)
    return likes.exists()

def get_fans(obj):
    """Получает всех пользователей, которые лайкнули `obj`."""
    obj_type = ContentType.objects.get_for_model(obj)
    return User.objects.filter(
        likes__content_type=obj_type, likes__object_id=obj.id)
  • */www.example.comserializers.py
from django.contrib.auth import get_user_model
from rest_framework import serializers

from .services import is_fan

User = get_user_model()

class FanSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = (
            'username',
        )

class ContentListSerializer(serializers.ModelSerializer):
    """Список контента"""

    class Meta:
        model = Content
        fields = ('title_ru', 'title_en', 'kinopoisk_id', 'rating', 'year')

class ContentDetailSerializer(serializers.ModelSerializer):
    """Информация о контенте"""
    is_fan = serializers.SerializerMethodField()

    class Meta:
        model = Content
        exclude = ('is_banned', 'id', 'kinopoisk_id')

    def get_is_fan(self, obj) -> bool:
        """Проверяет, лайкнул ли `request.user` твит (`obj`)."""
        user = self.context.get('request').user
        return is_fan(obj, user)
  • */www.example.commixins.py
from rest_framework.decorators import action
from rest_framework.response import Response

from .serializers import FanSerializer
from .services import get_fans, remove_like, add_like

class LikedMixin:
    @action(detail=True, methods=['POST'])
    def like(self, request, pk=None):
        """Лайкает `obj`."""
        obj = self.get_object()
        add_like(obj, request.user)
        return Response()

    @action(detail=True, methods=['POST'])
    def unlike(self, request, pk=None):
        """Удаляет лайк с `obj`."""
        obj = self.get_object()
        remove_like(obj, request.user)
        return Response()

    @action(detail=True, methods=['GET'])
    def fans(self, request, pk=None):
        """Получает всех пользователей, которые лайкнули `obj`."""
        obj = self.get_object()
        fans = get_fans(obj)
        serializer = FanSerializer(fans, many=True)
        return Response(serializer.data)
  • /查看*
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly

from .mixins import LikedMixin
from .models import Content
from .serializers import ContentListSerializer, ContentDetailSerializer

class ContentViewSet(LikedMixin, viewsets.ModelViewSet):
    """Вывод деталей контента"""
    queryset = Content.objects.filter(is_banned=False)
    permission_classes = (IsAuthenticatedOrReadOnly,)

    def get_object(self):
        kinopoisk_id = self.kwargs.get('pk')
        content = get_object_or_404(Content, kinopoisk_id=kinopoisk_id, is_banned=False)
        return content

    def get_serializer_class(self):
        if self.action == 'list':
            return ContentListSerializer
        elif self.action == 'retrieve':
            return ContentDetailSerializer
  • /网址*
from django.urls import path
from rest_framework.routers import DefaultRouter

from . import views

router = DefaultRouter()
router.register(r'content', views.ContentViewSet)

urlpatterns = router.urls
    • 问题描述:**

当我登录并希望使用链接获取所有内容或特定内容时:
http://127.0.0.1:8000/api/v1/content/?format=json
我成功了,但如果是这样(如果我注销帐户,则不会发生此错误:)
http://127.0.0.1:8000/api/v1/content/
错误:

Request Method: GET
Request URL: http://127.0.0.1:8000/api/v1/content/

Django Version: 4.1.6
Python Version: 3.10.5
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.postgres',
 'debug_toolbar',
 'django_elasticsearch_dsl',
 'rest_framework',
 'django_filters',
 'corsheaders',
 'rest_framework.authtoken',
 'djoser',
 'content']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware']


Traceback (most recent call last):
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 220, in _get_response
    response = response.render()
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/django/template/response.py", line 114, in render
    self.content = self.rendered_content
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/rest_framework/response.py", line 70, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/rest_framework/renderers.py", line 723, in render
    context = self.get_context(data, accepted_media_type, renderer_context)
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/rest_framework/renderers.py", line 654, in get_context
    raw_data_post_form = self.get_raw_data_form(data, view, 'POST', request)
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/rest_framework/renderers.py", line 553, in get_raw_data_form
    serializer = view.get_serializer()
  File "/Users/nikita/PycharmProjects/MoviePlanetPlatform/venv/lib/python3.10/site-packages/rest_framework/generics.py", line 110, in get_serializer
    return serializer_class(*args, **kwargs)

Exception Type: TypeError at /api/v1/content/
Exception Value: 'NoneType' object is not callable
py49o6xq

py49o6xq1#

我认为问题就在这里:

class ContentViewSet(LikedMixin, viewsets.ModelViewSet):
    ...

    def get_serializer_class(self):
        if self.action == 'list':
            return ContentListSerializer
        elif self.action == 'retrieve':
            return ContentDetailSerializer
        # only supports two actions

您可以将elif条件更改为else以处理所有操作用例,或者在所有条件都不匹配时添加另一个序列化程序。

相关问题