Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django rest framework TypeError: 'NoneType' object is not callable

/models.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 = 'Контент'

/services.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)

/serializers.py

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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)

/mixins.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)

/view

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

/urls

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

Problem description:

When I am logged in and I want to get all of the content or specific content using a link:

http://127.0.0.1:8000/api/v1/content/?format=json

I succeed, but if so (if I log out of my account, this error does not occur:)

http://127.0.0.1:8000/api/v1/content/

Error:

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

>Solution :

I think the problem is in here:

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

You can change the elif condition to else for handling all the action usecases or add another serializer when none of the conditions match.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading